PHP 7.0.6 Released

Sessions and security

External links: ยป Session fixation

HTTP session management is core of web security. All of mitigation should be adopted to make sure session security. Developer should enable/use applicable settings appropriately.

  • session.cookie_lifetime=0. 0 have special meaning. It tells browsers not to store cookie to permanent storage. Therefore, when browser is terminated, session ID cookie is deleted immediately. If developer set other than 0, it may allow other users to use the session ID. Most applications should use "0" for this. If auto login feature is required, implement your own secure auto login feature. Do not use session ID for it.
  • session.use_cookies=On and session.use_only_cookies=On. Although HTTP cookie has some problems, cookie is preferred way to manage session ID. Use only cookies for session ID management when it is possible. Most applications should use cookie for session ID.
  • session.use_strict_mode=On. This prevents session module to use uninitialized session ID. In other word, session module only accepts valid session ID generated by session module. It rejects session ID supplied by users. Session ID injection could be done by cookie injection via JavaScript permanently or temporarily. When transparent session is enabled, session ID could be injected via query string or form parameter. There is no reason to accept user supplied session ID, most applications must not accept user supplied uninitialized session ID.
  • session.cookie_httponly=On. Disallow access to session cookie by JavaScript. This setting prevents cookies stolen by JavaScript injection. It is possible to use session ID as CSRF protection key, but this is not recommended. For example, HTML source may be saved and sent to other users. Developer should not write session ID in web pages for better security. Almost all applications must use httponly attribute for session ID cookie.
  • session.cookie_secure=On. Allows access to session ID cookie only when protocol is HTTPS. If your web site is HTTPS only web site, you must enable this setting. Use of HSTS should be considered for HTTPS only web site.
  • session.gc_maxlifetime=[choose smallest possible]. GC is performed by probability. This setting does not guarantee old session deletion. Some session save handler modules do not use this setting. Refer to session save handler documentation for details. Although developer cannot rely on this setting, setting this to smallest possible value is recommended. Adjust session.gc_probability and session.gc_divisor so that obsolete sessions are deleted by appropriate frequency. If auto login feature is required, implement your own secure auto login feature. Do not use long life session ID for it.
  • session.use_trans_sid=Off. Use of transparent session ID management is not prohibited. You may use it when it is needed. However, disabling transparent session ID management would improve general session ID security by removing possibility of session ID injection and session ID leak.
  • session.referer_check=[your originating URL] When session.use_trans_sid is enabled, use of this setting is recommended if it is possible. It reduces risk of session ID injection. If your site is http://example.com/, set http://example.com/ to it. Note that when HTTPS is used, browser will not send referrer header. Browser may not send referrer header by configuration. Therefore, this setting is not reliable security measure.
  • session.cache_limiter=nocache. Make sure HTTP contents are not cached for authenticated session. Allow caching only when contents is not private. Otherwise, contents may be exposed. "private" may be used if HTTP content does not include security sensitive data. Note that "private" may leave private data cached by shared clients. "public" may be used only when HTTP content does not contain any private data at all.
  • session.hash_function="sha256". Stronger hash function will generates stronger session ID. Although hash collision is unlikely even with MD5 hash, developers should use SHA-2 or later hash functions for the task. Developers may use stronger hashes like sha384 and sha512.

The session module cannot guarantee that the information you store in a session is only viewed by the user who created the session. You need to take additional measures to actively protect the confidentiality of the session, depending on the value associated with it.

Assess the importance of the data carried by your sessions and deploy additional protections -- this usually comes at a price, reduced convenience for the user. For example, if you want to protect users from simple social engineering tactics, you need to enable session.use_only_cookies. In that case, cookies must be enabled unconditionally on the user side, or sessions will not work.

There are several ways to leak an existing session ID to third parties. A leaked session ID enables the third party to access all resources which are associated with a specific ID. First, URLs carrying session IDs. If you link to an external site, the URL including the session id might be stored in the external site's referrer logs. Second, a more active attacker might listen to your network traffic. If it is not encrypted, session IDs will flow in plain text over the network. The solution here is to implement SSL on your server and make it mandatory for users. HSTS should be used for this.

Since PHP 5.5.2, session.use_strict_mode is available. When it is enabled and save handler module supports it, uninitialized session ID is rejected and new session ID is created. This protects attack that force users to use known session ID. Attacker may paste links or send mail that contains session ID. e.g. http://example.com/page.php?PHPSESSID=123456789 If session.use_trans_sid is enabled, victim will start session using attacker provided session ID. session.use_strict_mode mitigates the risk.

Even though session.use_strict_mode mitigates risk of adoptive session management, attacker can force users to use initialized session ID which is created by attacker. All attacker has to do is initialize session ID prior to attack and keep it alive.

Session ID cookie could be set with domain, path, httponly, secure attributes. There is precedence defined by browsers. By using the precedence, attacker can set session ID that could be used permanently. Use of session.use_only_cookies will not solve this issue. session.use_strict_mode mitigates this risk. With session.use_strict_mode=On, uninitialized session ID will not be accepted. Session module creates new session ID always when session ID is not initialized by session module. This could result in DoS to victim, but DoS is better than compromised account.

session.use_strict_mode is good mitigation, but it is not enough mitigation for authenticated session. Developer must use session_regenerate_id() for authentication. session_regenerate_id() must be called prior to set authentication information to $_SESSION. session_regenerate_id() makes sure new session contains authenticated information stored only in new session. i.e. Errors during authentication process may save authenticated flag in old session.

Calling session_regenerate_id() function could result in personal DoS like use_strict_mode=On. However, DoS is better than compromised account. Session ID should be regenerated when user is authenticated at least. Session ID regeneration reduces risk of stolen session ID, thus is should be called periodically. Developer should not rely on session ID expiration. Attackers may access victim's session ID periodically to prevent expiration. Developers must implement their own expiration feature for old sessions.

Note that session_regenerate_id() does not delete old session by default. Old authenticated session may be available for use. If developer would like to prevent old authenticated session to be used by anyone, developer must destroy session by setting delete_old_session to TRUE. However, immediate old session deletion has unwanted side effect. Session could be vanished when there are concurrent connections to web application and/or network is unstable. Instead of deleting old session immediately, you may set short term expiration time in $_SESSION by yourselves. If user accesses to obsolete session(expired session), deny access to it.

session.use_only_cookies and proper use of session_regenerate_id() could cause personal DoS. When this is the case, you may ask users to remove cookies and warn users that there could be possible security issues. Attackers may set malicious cookies via vulnerable web application (i.e. JavaScript injection), vulnerable/malicious browser plugins, etc.

Developers must not use long life session ID for auto login as it increases risk of stolen session. Auto login should be implemented by developer. Use secure one time hash key as auto login key using cookie. Use secure hash stronger than SHA-2. e.g. SHA-256 or greater with random data from /dev/urandom or like. If user is not authenticated, check the one time auto login key is valid or not. If key is valid, authenticate user and set new secure one time hash key. Auto login key is long lived authentication key, this key should be protected as much as possible. Use path/httponly/secure attributes of cookie to protect. Developer must implement feature that disables auto login and removes unneeded auto login key cookie for users.

User Contributed Notes

Anurag Jain
7 years ago
Websites which have sensitive information need to be patched to ensure its not exploited because of session issues.

In earlier versions of apache cookie reliability was not assumed and hence the default method was always using url-rewrite which meant every url link, every form submission etc would have a PHPSESSID=<sessionid> passed along to inform the server about the active session. New versions have turned this off using

session.use_trans_sid = 0

in the /etc/php5/apache2/php.ini file.

Reasons?
Well one might safe the offline page as a bookmark or pass the link across to others not realizing that the session id information is also sent. So someone who quickly accesses these pages could possible get logged on, this was also true wrt search engines, and I guess in some cases it being seen as duplicate content as the same page will have a different session id every time the robots scan the website.

But having this set does not mean you are protected. Let me explain.
What prevents me from presetting the session id! Assume there is a banking site www.example.com which has a login screen at www.example.com/login.php
I can send you can email with a link to the bank site as http://www.example.com/login.php?PHPSESSID=12345
When you click on the link it presents the session id as 12345 rather then asking the server to generate a new one. This is called session fixation. Keep in mind even with session.use_trans_sid = 0 this will work as this sets it only not to use url-rewrite. To prevent this altogether set session.use_only_cookies = 1 which ensures that only cookies will be used, but this could cause problems when dealing with transaction which involve switch sites, i.e. siteA forwards to site B for payment which forwards to siteA for thank you, in which case a phpsessid inform might be used to revive the old session.

A good approach would always be to at the login screen and immediately post login to force a new session id generated using random numbers

session_start();
$newsessid = somerandomnumberfunction();
session_id($newsessid);

you can also use session_regenerate_id() function to generate a new id

session_start();
session_regenerate_id();

Also its always good to ensure every valid session is checked against an ip. One good method is to store the session id and remote ip information in a table, or better store the ip as a session variable itself, once the user logs in and ensure that this is continued for remaining pages for security. This ofcourse wont work when users use the same office or shared network as the ip to the outside world is the same.

https is always a good idea for sensitive sites, but keeping it persistent for all pages which use session is important if you really want a foolproof system else anyone can always sniff your packets.

So to quickly go through the bits

- set session.use_trans_sid = 0 in /etc/php5/apache2/php.ini file.
- Ensure you always use a new self generated session id on successful login attempt.
- Try setting session.use_only_cookies = 1 and check if all works fine.
- Use https throughout to ensure no one can sniff your session id.
- Store session id, remote IP information and compare for successive pages
bmearns at ieee dot org
7 years ago
In addition to ip-address binding not always being effective, it can also prevent users connecting through a proxy-pool from even being able to use your site. In such a scenario, a person's IP address may very well change with every access.

If you're handling anything remotely secure, the only safe option is HTTPS. If the data doesn't need to be that secure, than you should not allow a high-jacked session to do too much damage. Basically, don't assume that a person really is who they pretend to be just because the session says a person authenticated with a username and password: it may have been that person who logged in, but that doesn't mean it's still that person. So if you're going to do something like change passwords or something, require them to authenticate again on the same form.

Of course this needs to be done in some secure way, as well, so that the password is not just floating over the network. A good way to do this is sending a nonce (number-used-once) along with the form and some javascript to concatenate the nonce to the password, then perform a cryptographic hash of the combined string. The resulting valid-once "password" should then be sent instead of the plain text password. To be effective, you also need to prevent people from using the form if they don't have JavaScript enabled. You can do this by disabling the form fields in HTML, then re-enabling them in JavaScript.
justin at fatbird dot ca
7 years ago
IP checking is a sometimes useful feature with two limitations that are important to be aware of:

1. Anyone surfing behind a proxy (e.g., someone at work) will provide the proxy's IP, not his own.  Session ID replay attacks will not be prevented by IP checking for an attacker on the user's side of the proxy.

2. If the PHP application is behind a reverse proxy, the reverse proxy's IP address will be the only request IP seen by PHP, so IP checking is useless.
Olle Bergkvist
7 years ago
It is also quite important to (somehow) make sure that the cookies you're setting (including the session cookie) is only visible to the site that created it (or to other trusted sites only).

If the cookie's path is set to '/' (the whole domain), then any website on the same domain (might be lots of websites) _will_ get the cookie through HTTP headers and could possibly hijack your session.

One slightly acceptable protection would be to lock a session to one IP adress.
JonathanFeller at NOSPAMgmx dot ch
7 years ago
Perhaps, you would also like to timeout a session after some idle time. I noticed that session.gc_maxlifetime is not suitable for this. So I used this code to do the job:

<?php
if (!isset($_SESSION['timeout_idle'])) {
   
$_SESSION['timeout_idle'] = time() + MAX_IDLE_TIME;
} else {
    if (
$_SESSION['timeout_idle'] < time()) {   
       
//destroy session
   
} else {
       
$_SESSION['timeout_idle'] = time() + MAX_IDLE_TIME;
    }
}
?>
To Top