Session management safety is core of web application security. However, PHP's Session module is known to vulnerable to session adoption that enables session fixation for years.
When cookie is used for session, current session module does not validate session ID and accepts uninitialized one. This happens due to nature of web browsers that overrides cookie if multiple cookies are set for a request. Use of session_regenerate_id() CANNOT prevent session adoption/fixation.
There is user land solution that validates session data, but this method is not widely adopted. Even if the user land solution is adopted widely, there are risks that users do not use or users failed to implement it correctly.
Therefore, implementing strict session in PHP core is required for better Web application security.
https://gist.github.com/1379668
This patch adds
Compatibility issues are
problems. Using restrictive session ID string is better for other ps modules. IMHO)
You will see some tests are failing since they depend on adaptive session. By looking into failing test results, you can see this patch is generating new session ID if it's not a already initialized session. I'll modify these tests (set session.use_strict_mode=Off) and add some tests for new feature (new validate_sid() function for user and use_class save handler) after commit.
It removes session read failure retry code from php_session_initialize() . The retry code may cause infinite loop depending on save handler implementation. Some session save handlers may be using this to prevent adoption(?), but they should implement validate_sid() to prevent adoption from now on. With new code, there will never be infinite loops. Currently bundled save handlers are not using this feature.
This patch eliminates session adoption/fixation, but introduces targeted DoS attack. To disable DoS, deletion of possible offending cookies is needed.
Deletion method
Limitation
This patch adds validate_id() function to ps_modules (session save handler) that can check if the session ID is already initialized one or not. Bundled ps_modules are now have validate function and will never accept uninitialized session ID regardless cookie based or URL rewriter.
However, it is still possible users and ps_module writers may write improper save handlers, but it is user's responsibility that writes proper save handler that prevents session adoption.
There are cases that PHP cannot set cookie for sessions. If this happens, targeted DoS is possible. DoS is much better than stolen session, so users should accept this risk.
At user land, there will be no compatibility issues by disabling session.use_strict_mode. (i.e. session.use_strict_mode=0)
When strict mode is enabled, uninitialized session ID will be discarded. Therefore, applications that use adoptive session nature may not work. If malicious cookie that prevents new session ID is set, session module will keep trying to generate new session ID and session will not be usable.
session.safe_session_cookie=1 deletes possible malicious cookies that prevent new session ID. With this option, session modules send empty cookies for all possible domain and path.
This option may cause problems. For instance, when a user is using default session settings (i.e. using PHPSESSID for session name), it may delete legitimate cookies set by other applications. For this reason, this setting will be off by default.
There may be compatibility problem for internal session modules, if and only if it uses PS_MOD_SID()/PS_MOD_FUNCS_SID() for ps_module definition.
Module writers may use PHP_SESSION_API version ID to write portable ps_modules. New ps_module writers MUST use PS_MODE_SID()/PS_MOD_FUCS_SID() to support strict session.
Session is one of the most important feature to secure Web applications. However, current PHP session module is weak to session ID adoption, thus it is weak to session fixation.
Programmer can make adoptive session with user land code as follows.
Login code fragment: Code that adds session ID as validation key.
session_destory(); session_regenerate_id(); $_SESSION['valid_id'] = session_id();
Validation code: Code other than login. Check if session is properly initilized.
if ($_SESSION['valid_id'] !== session_id()) { die('Invalid use of session ID'); }
Alternatively, programmers may try to delete all possible cookies by sending empty session ID cookie.
Users who are using “user” save handlers can use open function to validate session ID is initialized one. If not, user can use session_regenerate_id() to create new ID.
Cookie that is used for session allows multiple cookies for a single request. When multiple cookies are set, browsers send multiple cookies WITHOUT domain and path information. Browser just send cookie header and there is no way to know which cookie is for which domain or path.
In addtion, there are no standards for sending multiple cookies. For example, IE has different order preference for sending cookies than Chrome/Firefox.
This behavior prevents use of session_regenerate_id()'s new cookie in some cases. PHP may use invalid session ID to initialize session. Session ID can be fixed (i.e. session fixation) without the validation code.
Session fixation can be used to take over session and compromise Web application security.
These are cases that adaptive session can be harmful. For all tests, all possible cookies for domain and path are set.
IE8: http://www.test.co.jp/path1/path2/
Cookie: C=%2Fwww%2Fdefault%2Fpublic; C=test.co.jp
IE9: http://www.test.co.jp/path1/path2/
Cookie: C=test.co.jp
IE9&Chrome: http://co.jp/path1/path2/
Cookie: C=co.jp
Most obvious case is setting cookie for sub path and “/”. Many applications sets cookie path according to application base directory. Setting cookie to “/” enables session fixation for many applications and installations.
CVE ID is assigned for this
CWE
CAPEC
Bug ID is #60491
2011-11-23 - 0.1 - just dumping the info from the original mail.
2011-11-24 - 0.2 - Correct “Reason why the validation key is required” description to be more accurate. Browser sends cookies, not cookie headers. Added example cookie headers to illustrate what's the problem.
2011-11-29 - 0.3 - Add DoS prevention.
2011-11-29 - 0.9 - Reorganize sections. Prepare for removing draft status.
2011-11-30 - 1.0 - Remove draft status.
2011-12-02 - 1.1 - Fix description for ps_module developers. Add session_id() warning.
2011-12-10 - 1.1 - Added CVE-ID