tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Henner Zeller <hen...@freiheit.com>
Subject 4.0/4.1: Session handling without cookies broken
Date Mon, 01 Jul 2002 08:42:10 GMT

Hi Guys,

I recently had the pleasure to work more with web applications and am now 
finding my way back to the server source. First impression: tomcat grew 
big, compared to JServ times .. but it seems, that its actual main aim, 
being a small, robust and fast servlet engine - isn't as dominant as it 
used to be ... (any folks here from the good ol' JServ times ? At least I 
see Pier quite often in the list).

Anyway, while making the wingS application framework 
(http://wings.mercatis.de/) work with Tomcat 4.x, I've 
found two bugs in TC, that go hand in hand, but basically make 
working with URL encoded sessions unpredictable or basically not working.
(If applications rely on URL-encoding, then these can be regarded as 
critical bugs).
Both bugs show up, if invalidated sessions come via cookies from the 
browser.

Bug #2 can have an impact as well if multiple session cookies for 
different servlet contextes on that hosts are available: only the first 
cookie is accepted. Didn't verify this, but if failing as expected, 
then this is a severe bug, because only the first servlet context will 
work with a session ...

These bugs are in both CVS versions of tomcat 4.0 and 4.1. 
One of the bugs can be easily fixed (fix given), the other bug 
probably needs a bit more work.

An example servlet that exposes both bugs is available.

*********
Bug #1 ; fix available
*********
 
The logic to determine whether a URL needs to be encoded in 
HttpServletResponse.encodeURL() is broken. In
HttpServletResponseBase.isEncodeable(String location), it
decides, that the URL needn't be encoded in the URL, if the
current ID comes from the cookie; see code-snippet from 
HttpServletResponseBase:
-------
    if (hreq.isRequestedSessionIdFromCookie()) {
        return (false);
    }
------

However, this does not take into account, that the session ID we got
might have been from some previous session that already is invalidated, 
i.e. is not valid. In this case isRequestedSessionIdFromCookie() will
return true, but this does not say anything if future (valid) sessions 
will come through the cookie.

The fix is easy: So the only way to check this correctly is:
---------
   if (hreq.isRequestedSessionIdFromCookie()
       && hreq.isRequestedSessionIdValid()) {
     return (false);
   }
---------

*********
Bug #2   ; detailed explanation but no fix yet
*********

There is a bug in the way, the session id is grabbed 
from the request. If there is more than one session id in the request 
-- in the URL and a Cookie, for instance -- the session id found in the 
cookie _always_ wins. This is a problem, if the browsers sends an 
invalidated cookie and you choose to use URL-encoding in a later session: 
even if the session id from the URL (via encodeURL(), that works only 
after fixing Bug #1) is valid, the application always gets the old 
and invalid session from the cookie instead of the valid session from the 
URL. 

The expected behaviour of course is: give preference to valid session 
id's if we get more than one session id.

The current session id grabbing-from-http-request algorithm is as follows 
(from HttpProcessor.java)

--------
1. get the session ID from the URL, if any.
     [HttpProcessor.parseRequest()]

2. go through the cookies. If there is _any_ 
   jsessionid - grab the _first one_ and 
   override the jsession-id found in the
   URL unconditionally. And set
      request.setRequestedSessionCookie(true);
      request.setRequestedSessionURL(false);
   even if the jsession id found in the
   cookie is the _same_ as found in the URL,
   in that case it should be 
   setRequestedSessionURL(true).
     [HttpProcessor.parseHeaders()]
---------

However, it should be something like:
---------
1. get the jsessionid from the URL, if any.
   if found there, setRequestedSessionURL(true)
   else setRequestedSessionURL(false)

2. go through the cookies. 
   FOREACH jsessionid found in the cookies:
     IF the sessionid found is valid in that context
            IF   found session id equals id already in request
               setRequestedSessionCookie(true)
            ELSE  (* see below)
               override the session id in request with the cookie-value
               setRequestedSessionCookie(true)
               setRequestedSessionURL(false)
            ENDIF
            BREAK FOREACH
      ELSE IF we have not found any session id before
               (either from URL or a previous cookie)
               // set at least some session id
               set the session id from the cookie
               setRequestedSessionCookie(true)
   END FOREACH
---------
This makes sure, that we find the valid session id, if there is more than
one session.

<discussion>
   I'd even suggest to give a higher priority to the
   URL encoded session: if the session id found in the URL is _valid_, 
   then ignore any valid session id in the cookies unless it is the same. 
   This enables to have two independant web-application instances in the 
   same browser: one with cookie, and one with URL-encoding (otherwise this 
   mode only works with two applications both with URL-encoding).
   This behaviour can be implemented by adding
   --
     IF not request.isRequestedSessionIdValid()
   --
   at the point denoted with (*) above.
</discussion>

In an attempt to fix this bug myself, I found, that at that stage it is 
not yet possible to check whether isRequestedSessionIdValid() 
[ implementation in HttpRequestBase ], since the context is not yet set 
in the HttpProcessor.process() stage -- so we don't have 
the manager and cannot check the session ID in that context for validity.
The context is set much later in the processing in 
StandardHostMapper.map() after having gone through several 
valves/Pipelines.

Since I don't know the internals of the tomcat (yet) I have no quick fix 
at hand, but for you guys its probably no big deal. Or give me an hint - 
then I'll fix it myself.

To demonstrate both of these bugs, I've written a small servlet, that goes 
through several steps to create two sessions; one as cookie, one with URL 
rewriting - just follow the instructions the servlet gives.
Note, that Bug #2 can only be checked thoroughly if Bug #1 has been fixed; 
otherwise Bug #1 does not do URL-encoding in the first place.

  <http://www.freiheit.com/users/hzeller/SessionBugDemonstration.java>

ciao,
 Henner.

PS:
  Interestingly, in tomcat 3.x the servlet works as expected; however even 
  there, the session id from the cookie seems to win, so that 
  getRequestedSessionId() returns a bogus (old) session-id and 
  isRequestedSessionIdFromCookie() returns true, even though the _valid_
  requested session id came from the URL. Still we receive the 
  correct HttpSession, whose getId() call returns the correct id.




--
To unsubscribe, e-mail:   <mailto:tomcat-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:tomcat-dev-help@jakarta.apache.org>


Mime
View raw message