<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>Session Management Basics</title> </head> <body><div class="manualnavbar" style="text-align: center;"> <div class="prev" style="text-align: left; float: left;"><a href="session.security.html">Sessions and Security</a></div> <div class="next" style="text-align: right; float: right;"><a href="session.security.ini.html">Securing Session INI Settings</a></div> <div class="up"><a href="session.security.html">Sessions and Security</a></div> <div class="home"><a href="index.html">PHP Manual</a></div> </div><hr /><div id="features.session.security.management" class="sect1"> <h2 class="title">Session Management Basics</h2> <div class="sect2" id="features.session.security.management.basic"> <h3 class="title">Session Security</h3> <p class="para"> 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 protect the confidentiality of the session, depending on the value associated with it. </p> <p class="para"> 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 <em>session.use_only_cookies</em>. In that case, cookies must be enabled unconditionally on the user side, or sessions will not work. </p> <p class="para"> There are several ways to leak an existing session ID to third parties. e.g. JavaScript injections, session ID in URLs, packet sniffing, physical access to device. 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/TLS on your server and make it mandatory for users. HSTS should be used for better security. </p> <blockquote class="note"><p><strong class="note">Note</strong>: <span class="simpara"> Even HTTPS cannot protect confidential data at all times. For example the CRIME and Beast vulnerabilities may enable an attacker to read the data. Also note that there are many networks that use HTTPS MITM proxies for audit purposes. Attackers may also set up such a proxy. </span> </p></blockquote> </div> <div class="sect2" id="features.session.security.management.non-adaptive-session"> <h3 class="title">Non-Adaptive Session Management</h3> <p class="para"> PHP's session manager is adaptive by default currently. Adaptive session manager has additional risks. </p> <p class="para"> Since PHP 5.5.2, <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> is available. When it is enabled, and the session save handler supports it, an uninitialized session ID is rejected and a new session ID is created. This prevents an attack that forces users to use known session ID. Attacker may paste links or send mail that contains the session ID. e.g. http://example.com/page.php?PHPSESSID=123456789 If <a href="session.configuration.html#ini.session.use-trans-sid" class="link">session.use_trans_sid</a> is enabled, the victim will start a session using the attacker provided session ID. <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> mitigates the risk. </p> <div class="warning"><strong class="warning">Warning</strong> <p class="simpara"> User defined save handlers can also support strict session mode by implementing session ID validation. All user defined save handlers must implement session ID validation. </p> </div> <p class="para"> The session ID cookie could be set with domain, path, httponly and secure attributes. There is precedence defined by browsers. By using the precedence, attacker can set session ID that could be used permanently. Use of <a href="session.configuration.html#ini.session.use-only-cookies" class="link">session.use_only_cookies</a> will not solve this issue. <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> mitigates this risk. With <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a>=On, the uninitialized session ID will not be accepted. </p> <blockquote class="note"><p><strong class="note">Note</strong>: <span class="simpara"> Even though <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> mitigates the risk of adoptive session management, attacker can force users to use initialized session ID which is created by attacker. e.g. JavaScript injection. This attack could be mitigated by this manual's recommendations. </span> <span class="simpara"> If you follow this manual, you will enable <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a>, use time-stamp based session management, and regenerate session ID by <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> with recommended procedure. If you do all of these, attacker generated session ID will eventually deleted. </span> <span class="simpara"> When obsolete session access happened, you should save all active session data for the user. It will be useful for investigation later. Then force the user to logout from all sessions. i.e. Require users to re-authenticate. This way, you can prevent attackers from keep abusing stolen sessions. </span> </p></blockquote> <div class="warning"><strong class="warning">Warning</strong> <p class="simpara"> Access to obsolete session data does not mean attack always. Unstable network and/or immediate active session deletion will cause legitimate users to use obsolete sessions. </p> </div> <p class="para"> Since PHP 7.1.0, <span class="function"><a href="function.session-create-id.html" class="function">session_create_id()</a></span> is added. This function could be used to prefix session ID by user ID to access active sessions for a user efficiently. Enabling <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> is very important with this setup. Otherwise, malicious users can set malicious session ID for other users. </p> <blockquote class="note"><p><strong class="note">Note</strong>: <span class="simpara"> Users prior to PHP 7.1.0 should use CSPRNG, e.g. /dev/urandom, or <span class="function"><a href="function.random-bytes.html" class="function">random_bytes()</a></span> and hash functions to generate new session ID. <span class="function"><a href="function.session-create-id.html" class="function">session_create_id()</a></span> has collision detection and generates session ID according to session INI settings. Use of <span class="function"><a href="function.session-create-id.html" class="function">session_create_id()</a></span> is preferred. </span> </p></blockquote> </div> <div class="sect2" id="features.session.security.management.session-id-regeneration"> <h3 class="title">Session ID Regeneration</h3> <p class="para"> <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> is good mitigation, but it is not enough mitigation. Developer must use <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> for session security. </p> <p class="para"> Session ID regeneration reduces risk of stolen session ID, thus <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> must be called periodically. e.g. Regenerate session ID for every 15 minutes for security sensitive content. Even when session ID is stolen, either legitimate user or attacker session will be expired. i.e. User or attacker access will generate obsolete session access error. </p> <p class="para"> Session ID must be regenerated when user is authenticated. <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> must be called prior to set authentication information to $_SESSION. (Since PHP 7.0.0, <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> saves current session data automatically in order to save time-stamp/etc to current session.) Make sure only new session contains authenticated flag. </p> <p class="para"> Developer must NOT rely on session ID expiration by <a href="session.configuration.html#ini.session.gc-maxlifetime" class="link">session.gc_maxlifetime</a>. Attackers may access victim's session ID periodically to prevent expiration and keep exploiting victim's session ID including authenticated sessions. </p> <p class="para"> Instead, you must implement time-stamp based session data management by yourself. </p> <div class="warning"><strong class="warning">Warning</strong> <p class="simpara"> Although session manager can manage time-stamp transparently, but this feature is not implemented. Old session data must be kept until GC. At the same time, developers must make sure obsolete session data is removed. However, developers must NOT remove active session data immediately. i.e. Never call <em>session_regenerate_id(true);</em> and <span class="function"><strong> session_destroy()</strong></span> for active session. This may sound contradictory, but this is the mandatory requirement. </p> </div> <p class="para"> <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> does not delete old session by default. Old authenticated session may be available for use. Developers must prevent old session to be used by anyone, must prohibit access to obsolete session data by themselves using time-stamp. </p> <div class="warning"><strong class="warning">Warning</strong> <p class="simpara"> Immediate active session removal has unwanted side effects. Session could be vanished when there are concurrent connections to web application and/or network is unstable. </p> <p class="simpara"> Possibly malicious access cannot be detected with immediate active session removal also. </p> <p class="simpara"> Instead of deleting old session immediately, you must set short term expiration time (time-stamp) in $_SESSION, and prohibit access to the session data by yourself. </p> <p class="simpara"> You must not prohibit access to old session data immediately after <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span>. It must be prohibited a little later. e.g. A few seconds later for stable wired network. A few minutes later for unstable network such as mobile or WiFi. </p> <p class="simpara"> If user accesses to obsolete session(expired session), deny access to it. It is recommended to remove authenticated status from all of the users' session because it is likely an attack. </p> </div> <p class="para"> Proper use of <a href="session.configuration.html#ini.session.use-only-cookies" class="link">session.use_only_cookies</a> and <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> could cause personal DoS by undeletable cookies set by attackers. 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, vulnerable/malicious browser plugins, physically compromised device, etc. </p> <div class="warning"><strong class="warning">Warning</strong> <p class="simpara"> Do not misunderstand the DoS risk. <em>use_strict_mode=On</em> is mandatory for general session ID security! All sites are advised to enable <em>use_strict_mode</em>. </p> <p class="simpara"> DoS could happen only when the account is under attack by crackers. JavaScript injection vulnerability in application is the most common cause. </p> </div> </div> <div class="sect2" id="features.session.security.management.session-data-deletion"> <h3 class="title">Session Data Deletion</h3> <p class="para"> Obsolete session data must be inaccessible and deleted. Current session module does not handle this well. </p> <p class="para"> Obsolete session data is better to be removed as soon as possible. However, active sessions MUST NOT be removed immediately. To satisfy these requirements, you MUST implement time-stamp based session data management by yourself. </p> <p class="para"> Set and manage expiration time-stamp in $_SESSION. Prohibit access to obsolete session data. When obsolete session data access is detected, it is advised to remove all authenticated status from the user's sessions and force them to re-authenticated. Obsolete session data access could be an attack. To do this, you must keep track active sessions per user. </p> <blockquote class="note"><p><strong class="note">Note</strong>: <span class="simpara"> Access to obsolete session could happen by unstable network and/or concurrent access to web site also. Server tried to set new session ID via cookie, but Set-Cookie packet may not be reached to client due to lost connection. One connection may issue new session ID by <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span>, but another conncurrent connection may not get the new session ID yet. Therefore, you must prohibit access to obsolete session a while later. i.e. Time-stamp based session management is mandatory. </span> </p></blockquote> <p class="para"> In short, do not destroy session data by <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> nor <span class="function"><a href="function.session-destroy.html" class="function">session_destroy()</a></span>, but use time-stamp to control access to session data. Let <span class="function"><a href="function.session-gc.html" class="function">session_gc()</a></span> to remove obsolete data from session data storage. </p> </div> <div class="sect2" id="features.session.security.management.session-locking"> <h3 class="title">Session and Locking</h3> <p class="para"> Session data is locked to avoid races by default. Locking is mandatory to keep session data consistent across requests. </p> <p class="para"> However, locking can be abused by attacker to perform DoS attacks. To mitigate risks of DoS by session lock, minimize lock. Use read only sessions when session data update is not required. Use 'read_and_close' option with <span class="function"><a href="function.session-start.html" class="function">session_start()</a></span>. <em>session_start(['read_and_close'=>1]);</em> Close session as soon as you finish updating $_SESSION by using <span class="function"><a href="function.session-commit.html" class="function">session_commit()</a></span>. </p> <p class="para"> Current session module does not detect $_SESSION modification while session is inactive. It is your responsibility not to modify $_SESSION when session is inactive. </p> </div> <div class="sect2" id="features.session.security.management.active-sessions"> <h3 class="title">Active Sessions</h3> <p class="para"> Developers should keep track active sessions per user and notify the user how many active sessions, from which IP (and area), how long is active, etc. PHP does not keep track these. You are supposed to do so. </p> <p class="para"> There are number of ways for the implementation. You may setup a database that keeps track required data and store information to it. Since session data is GCed, you have to take care of GCed data to maintain the active session database consistency. </p> <p class="para"> One of the simplest implementation is "User ID prefixed session ID" and store required information to $_SESSION. Many databases have good performance for selecting string prefix. You can use <span class="function"><a href="function.session-regenerate-id.html" class="function">session_regenerate_id()</a></span> and <span class="function"><a href="function.session-create-id.html" class="function">session_create_id()</a></span> for this. </p> <div class="warning"><strong class="warning">Warning</strong> <p class="simpara"> Never use confidential data as prefix. If user ID is confidential, consider to use <span class="function"><a href="function.hash-hmac.html" class="function">hash_hmac()</a></span>. </p> </div> <div class="warning"><strong class="warning">Warning</strong> <p class="simpara"> Enabling <a href="session.configuration.html#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> is mandatory for this setup. Make sure it is enabled, otherwise active session database can be compromised. </p> </div> <p class="para"> Time-stamp based session management is mandatory to detect obsolete session access. When access to obsolete session is detected, you should remove authentication flags from all of active sessions for the user. This prevents attackers to keep exploiting stolen session. </p> </div> <div class="sect2" id="features.session.security.management.session-and-autologin"> <h3 class="title">Session and Auto Login</h3> <p class="para"> Developers must NOT use long life session ID for auto login because it increases risk of stolen session. Auto login should be implemented by developer. </p> <p class="para"> Use secure one time hash key as auto login key using <span class="function"><a href="function.setcookie.html" class="function">setcookie()</a></span>. Use secure hash stronger than SHA-2. e.g. SHA-256 or greater with random data from <span class="function"><a href="function.random-bytes.html" class="function">random_bytes()</a></span> or /dev/urandom. </p> <p class="para"> 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 must be able to be used only once. i.e. Never reuse auto login key, generate new auto login key always. </p> <p class="para"> Auto login key is long life authentication key, this key should be protected as much as possible. Use path/httponly/secure cookie attributes to protect. i.e. Never transmit auto login key unless it is required. </p> <p class="para"> Developer must implement feature that disables auto login and removes unneeded auto login key cookie. </p> </div> <div class="sect2" id="features.session.security.management.csrf"> <h3 class="title">CSRF(Cross Site Request Forgeries)</h3> <p class="para"> Session and authentication does not protect against CSRF attack. Developers must implement CSRF protection by themselves. </p> <p class="para"> <span class="function"><a href="function.output-add-rewrite-var.html" class="function">output_add_rewrite_var()</a></span> can be used for CSRF protection. Refer to the manual page for details. </p> <blockquote class="note"><p><strong class="note">Note</strong>: <span class="simpara"> PHP prior to 7.2.0 uses the same output buffer and INI setting as trans sid. Therefore, use of <span class="function"><a href="function.output-add-rewrite-var.html" class="function">output_add_rewrite_var()</a></span> with PHP prior to 7.2.0 is not recommended. </span> </p></blockquote> <p class="para"> Most web application frameworks support CSRF protection. Refer to your web application framework manual for details. </p> </div> </div><hr /><div class="manualnavbar" style="text-align: center;"> <div class="prev" style="text-align: left; float: left;"><a href="session.security.html">Sessions and Security</a></div> <div class="next" style="text-align: right; float: right;"><a href="session.security.ini.html">Securing Session INI Settings</a></div> <div class="up"><a href="session.security.html">Sessions and Security</a></div> <div class="home"><a href="index.html">PHP Manual</a></div> </div></body></html>