#874: [PATCH] Fix potential denial of service in session handling
-------------------------------------+--------------------------------------
Reporter:
filter-...@mbox.bz | Owner: no_mind
Type: defect | Status: new
Priority: normal | Milestone:
Component: sessions | Keywords: session cookie
-------------------------------------+--------------------------------------
CherryPy with 'tools.sessions.on = True' will currently create a new
session for each request that does not come with a valid session cookie.
This is undesirable because every session consumes server ressources (RAM,
diskspace or slots in a LRU) and a malicious attack, or simply a high-
traffic situation, can lead to a denial of service for legitimate users
due to ressource starvation.
For example, a simple apachebench (ab) performing normal GET-requests can
create thousands of sessions per second without breaking a sweat.
The attached patch mitigates the problem creating sessions only when
absolutely necessary, that is when data has been written to the session,
e.g. via ''cherrypy.session['foo'] = bar''.
This gives full control over the session lifecycle to the application
developer, who must still pay attention to not create sessions carelessly.
As a rule of thumb: Create sessions only after a successful login or
captcha verification. Pages that are freely accessible for hammering
should never create a session.
There is one backwards-incompatible change in this Changeset:
Custom Session implementations (including subclasses of !RamSession,
!MemcachedSession etc.) that override !__init!__() must add a check to the
constructor to bail out if the session "disappears during initialization".
See an example:
{{{
class MyRamSession(RamSession)
def __init__( self, id=None, **kwargs ):
RamSession.__init__( self, id, **kwargs )
### this block is new
if
self.id is None:
# this was only a test for existence, bail out
return
# do your thing here as usual...
}}}
As you can see this is not a big change but one you must be aware of or
your custom Session impl will break.
Other than that the patch should be fully backwards compatible.
These are the new semantics for all possible cases:
{{{
Request : No session cookie
Controller: No write to the session
Result : No session is created, no cookie is sent
Request : No session cookie
Controller: Writes to the session
Result : Session is created, browser cookie sent
Request : Valid session cookie (session exists)
Controller: Writes to the session
Result : Session is maintained as usual
Request : Valid session cookie (session exists)
Controller: No write to the session
Result : Session is maintained as usual
Request : Invalid session cookie (invalid, expired or non-existing
sessionid)
Controller: No write to the session
Result : No session is created, browser cookie is cleared
Request : Invalid session cookie (invalid, expired or non-existing
sessionid)
Controller: Writes to the session
Result : Session is created, browser cookie is updated
}}}
TESTING:
I have confirmed all cases manually with firefox/firebug against my
subclass of !MemcachedSession and a vanilla !RamSession. It works. The
automatic tests unfortunately crash & burn, no idea what's going on there
(fumanchu, can you take a look?).
Feedback and improvements welcome...
--
Ticket URL: <
http://www.cherrypy.org/ticket/874>
CherryPy <
http://www.cherrypy.org>
CherryPy - a pythonic, object-oriented HTTP framework