Yii's sessions can be a source of DoS

[size="5"]the problem[/size]

yii current behavior is to save entries for empty sessions

running several hits on a yii web app without saving the cookie will create a session for each

and no matter what sessions class one uses it will be a source of DoS

  • cache-based sessions will get out of memory

  • file-based sessions will get at least the minimal filesystem-specific block and node entry which is not less than 512 bytes

  • db-based sessions will get so many inserts in the sessions table and its index consuming both CPU and disk space

the following example will create 1 million sessions in seconds

example 1:




for i in $( seq 1000 )

do

ab -c 10 -n 1000 my-site-url

done



another way to do that

example 2:




for j in $( seq 10000 )

do

  for i in $( seq 100 )

  do

    wget -O - my-site-url 1>/dev/null 2>&1 &

  done

  wait

done



[size="5"]how to fix that ?[/size]

something similar to OS COW [wikipedia:Copy-on-write]

we only allocate a session entry only when it’s not empty (ie. something assigned to it, eg. a flash message)

and as long as it’s empty we only need to know if this session id was original created by us

this can be done using secure cookies or having the value something like {$toke}!${sessions_id}

where token is hmac of session_id and some secret param

Nice thoughts - but isn’t this rather a problem that should be fixed on PHP level? I mean, isn’t any PHP app that uses sessions exposed to this problem?

Yii already has session cookie hi-jack prevention, css and csrf protection, so why not? :)

(Emphasis add by me, D.M.)

1/ Secure cookies wouldn’t help because (as far as I understood) a central precondition of the described DoS is, that the client does not accept cookies.

2/ A malicous client would simply not include the session id in the GET request.

(Besides: How would you differentiate between an empty and an expired Session?)

3/ The Framework is the wrong place to mitigate this problem.

@mike: AFAIK not just PHP, but every web scripting language. If you want to persist state, it must be stored somewhere. Even if it is memory.

Best,

– David

Instead of pointing your script to a simple index-page, you could also point the script to a page which consumes much cpu or executes many db-queries. This would bring a site down faster than creating dummy sessions.

Protection against such DoS-attempts should be dealt with at system/webserver level - or in best case with a hardware based solution. Such "evil" connections should never reach the php-parser if possible.

If there’s no knowledge or money for a good protection, then one could simply make a little PHP snippet that protects against http-based DoS attacks (eg exit() if ip connected more than X times within X seconds).

Have to correct myself:

The client not passing the session id in the GET request is not a problem. To differentiate between empty and expired session requires encoding a timestamp in the session id.

This could work but seems a lot of useless work because the solution is simple: Don’t create session unless you have to.

And: If your server can’t handle 1.000.000 requests I assume dummy sessions are the least thing to worry about. Think about memory consumption, or as mentioned, expansive db queries.

A PHP script the keeps track of the number of connections per IP is, of course, not a substitution for protection at the lower level. Because you would have to store the number of connections per IP somewhere…

maybe setting autoStart=false would solve much of it

although I would prefer a different approach

> 1/ Secure cookies wouldn’t help because (as far as I understood) a central precondition of the described DoS is, that the client does not accept cookies.

in my proposal

we don’t allocate the session, we just create a secure cookie in other words nothing allocated server side

> 2/ A malicous client would simply not include the session id in the GET request.

then he will cost us a call to uniqid() to generate him a cookie, no resources would be consumed

> Besides: How would you differentiate between an empty and an expired Session?

why do I need to do that ?

here is a suggested solution using a class called LazyCacheHttpSession, one might use