36

I've got some strange bug: when I open page first time in some browser all references has jsessionid parameter (like <a href="/articles?name=art&jsessionid=5as45df4as5df"..>).

When I press F5 or refresh the page by any other ways all that stuff is disappeared and everything works fine until I close my browser (and all tabs should be closed too). When I open it again I see this strange jsessionid parameter.

I use jstl <c:url..> tag for creating all URLs.

I've read some time ago that jsessionid is an alternative to cookies if cookies are disabled, but cookies are enabled and I actually don't use cookies.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Roman
  • 64,384
  • 92
  • 238
  • 332

7 Answers7

42

This isn't a bug, it's by design. When a new session is created, the server isn't sure if the client supports cookies or not, and so it generates a cookie as well as the jsessionid on the URL. When the client comes back the second time, and presents the cookie, the server knows the jsessionid isn't necessary, and drops it for the rest of the session. If the client comes back with no cookie, then the server needs to continue to use jsessionid rewriting.

You may not explicitly use cookies, but you do implicitly have a session, and the container needs to track that session.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • that's nice, but all my css look like "link rel=".." href="/mysite/css/styles.css?jsessionid=as2dfs4df". can I turn off this default behavior or it would be a bad practice and I should fix my css-loading? – Roman Jun 25 '09 at 19:18
  • 3
    That's going to be dependent on which container you're running in – skaffman Jun 25 '09 at 19:24
  • But, is not, in general, URL Rewriting with JSESSIONID in the url very very insecure. On a TLS/HTTP**S** connection cookies will be encrypted too, so JSESSIONID is not exposed to wire tapping. But even on an HTTP**S** connection with JESSIONID in the **url**, the JSESSIONID is entirely exposed to wire tapping. That seems like a serious security concern. Why is this approach ever taken even if cookies are disabled. – samshers Dec 01 '20 at 14:37
28

As explained in skaffman's answer, its not a bug. Its an expected behavior.

In your question the jsessionid is appended as a parameter, which is not the case.
Using
<c:url value="/"/>
will generate something like the following: /some/;jsessionid=E85FAC04E331FFCA55549B10B7C7A4FA.
So using
<link href="<c:url value="/"/>stylesheets/style.css" rel="stylesheet" type="text/css"/>
will generate
/some/;jsessionid=E85FAC04E331FFCA55549B10B7C7A4FAstylesheets/style.css
, so your server cannot find the resource available.

The best workaround that I found is to use ${pageContext.request.contextPath} instead of <c:url value="/"/>. So in the previous example, you would have
<link href="${pageContext.request.contextPath}/stylesheets/style.css" rel="stylesheet" type="text/css"/>
that will generate
/some/stylesheets/style.css.

This solution is container independent (whereas the servlet specification v3 compliant container - like Tomcat - solution is not). Filtering the response url feels like a hack, cause you need to change a default behavior. But all depends on what you need and want to achieve.

despot
  • 7,167
  • 9
  • 44
  • 63
20

On Tomcat 7 or any servlet specification v3 compliant server you can disable jsessionid in URL by adding following to the web.xml of your application

<session-config>
    <tracking-mode>COOKIE</tracking-mode>
</session-config>
maneesh
  • 1,092
  • 1
  • 8
  • 11
7

Here's a nasty workaround in flavor of a Filter so that you will never see the jsessionid in URL whenever the client supports cookies.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    HttpSession session = req.getSession();

    if (session.isNew()) {
        // New session? OK, redirect to encoded URL with jsessionid in it (and implicitly also set cookie).
        res.sendRedirect(res.encodeRedirectURL(req.getRequestURI()));
        return;
    } else if (session.getAttribute("verified") == null) {
        // Session has not been verified yet? OK, mark it verified so that we don't need to repeat this.
        session.setAttribute("verified", true);
        if (req.isRequestedSessionIdFromCookie()) {
            // Supports cookies? OK, redirect to unencoded URL to get rid of jsessionid in URL.
            res.sendRedirect(req.getRequestURI().split(";")[0]);
            return;
        }
    }

    chain.doFilter(request, response);
}

Map it on /* or whatever URL pattern which require session management.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • hi BalusC, thanks for the answer! I don't do web-development currently, but I'll try your solution on one of my old projects which had this problem. Could you explain a little (or give a correspondent link) the concept of encoded/not encoded URL? Why is it matter? The other thing here for which I lack knowledge to understand it is "verified" attribute for session. Who and when normally set it? – Roman Oct 26 '10 at 06:36
  • Skaffman has answered the need for jsessionid in URL. The `verified` attribtue is just there to prevent the filter from running in an infinite loop once the cookie support has been verified. You're free to rename it to something else. – BalusC Oct 26 '10 at 10:43
2

If you have a common wrapper page that all pages use (for me it was common.inc) you can add session="false" to your <%@ page to remove the sessionid.

Example common.inc

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" session="false" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="ab" tagdir="/WEB-INF/tags" %>

<c:set var="contextPath" scope="request" value="${ pageContext.request.contextPath }" />
<c:set var="assetPath" scope="request" value="/assets" />
<c:set var="debugEnabled" scope="request" value="${ applicationDebugProperties.debugEnabled }" />

Alternatively.. set the value of c:url to a variable and use c:out escapeXml="false" to output the variable and this will remove the sessionid.

Example:

<c:url value=${url} var="image"/>
<c:out var=${image} escapeXml="false"/>

Alternatively, you can add this to your Apache configuration to truncate the sessionid.

ReWriteRule ^/(\w+);jsessionid=\w+$ /$1 [L,R=301]
ReWriteRule ^/(\w+\.go);jsessionid=\w+$ /$1 [L,R=301]
davidcondrey
  • 34,416
  • 17
  • 114
  • 136
1

One workaround is not to use <c:url>, but to use ${request.contextPath}/path

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
0

Unfortunately the only way I have found around this is to add a filter to your application that will strip out the jsessionid parameter. Its particularly annoying if you are creatinga public website and want th esearch engines to index your pages.

I do not believe that tomcat (if that's what you're using) can be configured to not add this to your url. I can't say for the other servers though.

However, note that if you do create the filter and you then require session management and the user has cookies turned off you will run into problems.

Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
  • It's interesting that his example has jsessionid as a parameter in the URL. I haven't seen the before. Tomcat puts it in as a postfix to the URL (e.g. my/path;jsessionid=...&x=y), which I thought was what the servlet spec required. – skaffman Jun 25 '09 at 19:36
  • Actually I've made a mistake, it's not a parameter but I forgot the exactly format at that moment – Roman Jun 27 '09 at 07:57
  • Tomcat 7 can be used for this. Tomcat 6.0.30 will have this feature. – Wes Nov 22 '10 at 23:21