This blog is of course inspired by Jason's ASP .Net blog. I figured as the PHP guy in the group, I may as well cover what he did for .Net from the PHP side.
PHP's default session mechanism is rather simple and effective. The php.ini file configures how sessions work. Many of the parameters can be overridden within your PHP code, or .htaccess files can be used to create more fine grained configurations for particular directories. The session module is part of PHP by default, but can be disabled at compile time. By default, the session data is saved in files. The directory the session data is stored in is again configured in php.ini and defaults to /tmp (not the best choice, but more about that in a later blog).
Much of the session module can be adjusted, or custom code can be used to store session data in a database.
Like Jason noted for .Net, sessions and authentication are two different things in PHP as well. It is up to the developer to use sessions to store the user's identifier.
Let's follow Jason's outline, and talk about session fixation first!
PHP provides a number of defenses to prevent session fixation. First of all, the lifetime of a session can be limited in php.ini, or by simply using runtime configuration directives. The one "gotcha" here is that some developers mistake the cookie lifetime for the session lifetime. The session lifetime is the part that counts. It is adjusted via gc_maxlifetime parameters. The "gc" (Garbage Collection) parameters are a bit hard to grasp for someone new to PHP. First of all, it is important to understand that nothing happens in PHP unless a page is rendered. Session data will survive indefinetly if the server is idle. Whenever a page is displayed and a session is initiated, the garbage collection functions run and clean up old session data. There are a total of three parameters that determine how this is done:
gc_probability and gc_divisor: How likely is it that the garbage collection is performed. The probability is calculated as gc_probability/gc_divisor. The default is 1/100, which may be a bit a lot probablility if you only have 100 page views per hour. But if you have 100 page views per second, this is perfectly fine.
gc_maxlifetime: This parameter defaults to 1440 seconds (15 minutes). After 15 minutes of inactivity, the session is considered for garbage collection.
So in short: Using default parameters, the session is deleted within 100 page views after the 15 minute time out expired, assuming that each page view initiates a session.
What does this mean for session fixation and reusing session data: The time window is about 15 minutes by default, which is appropriate for most applications.
PHP does allow for a "referrer check". Sessions will only be considered if the referrer contains the string defined using the "referer_check" configuration parameter. By default, this parameter is empty. This is a very powerful way to block many session fixation attacks.
It is also rather simple to change the session ID in PHP. session_regenerate_id will create the new session and move the data. Take care to set the optional parameter to "true". Otherwise, the old session will not be deleted. For the paranoid, it is as easy as adding "session_regenerate_id(true)" to your header file. (and wait for entropy starvation to set in ? ).
Now what about the attacker obtaining a valid session id? PHP allows for sessions to be delivered via the URL, or cookies. URL based sessions are disabled by default via the "use_only_cookies" parameter. The cookie itself is configured via php.ini.
Cookies can simply be configured as http_only and secure via php.ini. No need for extra code on this one.
Another item not discussed (yet?) by Jason is the session ID generation. PHP's session ID generation is reasonably secure by default. It is possible to define the source of the entropy used to create sessions (/dev/random or /dev/urandom), how many bytes of entropy are used and which hash function is used. Plenty of ways to mix it up!
There is a lot more to talk about when it comes to PHP sessions. Let's see what Jason is up to next! Also note that the facts above are valid for later versions of PHP (5 and later). Maybe I should also write about suhosin one of these days, an excelent PHP hardening module.