rfc:session-create-id
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:session-create-id [2016/04/08 23:47] – Add reference yohgaki | rfc:session-create-id [2020/03/26 12:47] (current) – this RFC has been implemented long ago cmb | ||
---|---|---|---|
Line 2: | Line 2: | ||
* Version: 0.1 | * Version: 0.1 | ||
* Created Date: 2016-04-07 | * Created Date: 2016-04-07 | ||
- | * Modified Date: 2016-04-07 | + | * Modified Date: 2016-08-10 |
* Author: Yasuo Ohgaki < | * Author: Yasuo Ohgaki < | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | Session ID is created by session internal | + | Session ID is created by session internal |
===== Proposal ===== | ===== Proposal ===== | ||
Line 16: | Line 16: | ||
string session_create_id([string $prefix]) | string session_create_id([string $prefix]) | ||
- | session_create_id() will create new session ID by | + | NOTE: Prefix length is not considered as a part of session.sid_length. Session |
- | * Default internal function(php_session_create_id()) when session is not active. | + | session_create_id() will create new session ID by |
- | * User defined | + | |
- | Session ID collision is detected upon session_start(). Therefore, different | + | * Default internal function(php_session_create_id()) when session |
+ | * Save handler | ||
+ | * Additionally, | ||
- | Note: Session | + | Note: User defined session |
http:// | http:// | ||
- | It's not documented because Object based save handler has non standard method name. i.e. create_sid() rather than createSid(). Rename will be proposed by different RFC. If you would like to see how it is used, please refer to phpt files. | + | <del>It's not documented because Object based save handler has non standard method name. i.e. create_sid() rather than createSid(). Rename will be proposed by different RFC.</ |
* https:// | * https:// | ||
Line 34: | Line 35: | ||
==== Use case ==== | ==== Use case ==== | ||
- | Prefix session ID by user id. | + | Prefix session ID by user id. This could be useful to search active session IDs for a user. |
<code php> | <code php> | ||
<?php | <?php | ||
function create_logged_in_session($uid) { | function create_logged_in_session($uid) { | ||
- | // Mark obsolete session as obsolete. | + | // Mark obsolete session as obsolete. Timestamp based session management is mandatory. |
$_SESSION[' | $_SESSION[' | ||
- | // Prepare new logged | + | // Make sure old session does not have ' |
- | | + | |
- | session_commit(); | + | |
- | ini_set(' | + | // Session is active here. It is safe to generate new session ID while session |
+ | // because session ID collision | ||
+ | $sid = session_create_id($uid.' | ||
+ | |||
+ | // Save and close old session. | ||
+ | session_commit(); | ||
+ | |||
+ | // use_strict_mode should be enabled by default for session security. | ||
+ | // However, it must be disable to use custom session ID. | ||
+ | ini_set(' | ||
+ | |||
+ | // Set your own session ID and start session. | ||
session_id($sid); | session_id($sid); | ||
- | session_start(); | + | |
+ | | ||
+ | |||
+ | | ||
+ | if (session_id() !== $sid) { | ||
+ | throw new Exception(' | ||
+ | } | ||
+ | |||
+ | $_SESSION[' | ||
} | } | ||
function my_session_start() { | function my_session_start() { | ||
+ | // Should enable use_strict_mode for security reasons. | ||
+ | ini_set(' | ||
+ | |||
session_start(); | session_start(); | ||
+ | | ||
// Check obsolete session | // Check obsolete session | ||
if ($_SESSION[' | if ($_SESSION[' | ||
throw new Exception(' | throw new Exception(' | ||
- | } | + | } |
} | } | ||
?> | ?> | ||
</ | </ | ||
- | If session is stored | + | If session |
+ | |||
+ | ===== Discussions ===== | ||
+ | |||
+ | == Should have str_bin2readable() instead of session_create_id() == | ||
+ | |||
+ | Internal php_bin_to_readable() function that converts binary to chars has issues. | ||
+ | - It's not designed to reversible. i.e. str_readable2bin() is not possible. It cannot be implemented usable way at least. | ||
+ | - session_create_id() is mandatory function for session ID validation enabled user save handlers. There should be default session ID creation function. Otherwise, users have to implement by themselves and users could easily implement improper or broken session_create_id() function. | ||
+ | |||
+ | == User land session_create_id() is easy == | ||
+ | |||
+ | It would be easy with quick, dirty and insecure way. However, proper, precise and compatible session_create_id() is complex to do the exactly what proposed session_create_id() does. | ||
+ | |||
+ | <code php> | ||
+ | function session_create_id(string $prefix) | ||
+ | { | ||
+ | $encoded = base64_encode(random_bytes(ini_get(' | ||
+ | // Use same charset as PHP | ||
+ | $sid = substr(rtrim(strtr($encoded, | ||
+ | ini_get(' | ||
+ | // This code does not consider session.hash_bits_per_character. | ||
+ | // It must be handled also, but omitted here. | ||
+ | // In addition, above code reduces session ID security by | ||
+ | // eliminating certain patterns of bits. i.e. Removing | ||
+ | // certain chars in BASE64 encoding string removes certain | ||
+ | // patterns of bits. As a result, randomness of session ID | ||
+ | // is spoiled. | ||
+ | |||
+ | $sid .= $prefix; | ||
+ | |||
+ | // Now validate SID so that it does not have collisions | ||
+ | when session is active, connect to database and validate SID | ||
+ | try to fetch sid | ||
+ | if sid is there | ||
+ | try again to generate SID few times | ||
+ | if SID validation failed | ||
+ | fatal error | ||
+ | return safe SID | ||
+ | when session is inactive | ||
+ | return unvalidated SID | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Something like above code is **required** to implement recommended user session save handlers currently. | ||
+ | |||
+ | == The default 128 bits Session ID is large enough to ignore collisions == | ||
+ | |||
+ | Brute force session ID hijack risk is described here. | ||
+ | https:// | ||
+ | |||
+ | The expected number of seconds required to guess a valid session | ||
+ | identifier is given by the equation: | ||
+ | |||
+ | (2^B+1)/ | ||
+ | |||
+ | Where: | ||
+ | |||
+ | B is the number of bits of entropy in the session identifier | ||
+ | A is the number of guesses an attacker can try each second | ||
+ | S is the number of valid session identifiers that are valid and | ||
+ | available to be guessed at any given time | ||
+ | |||
+ | It says | ||
+ | |||
+ | '' | ||
+ | |||
+ | 292 years may sound long enough. However, even though the document explicitly does not states " | ||
+ | |||
+ | Let me paraphrase OWASP' | ||
+ | |||
+ | '' | ||
+ | |||
+ | NOTE: It's about probability. Expectation is "on average" | ||
+ | |||
+ | Assumption for security should be pessimistic. OWASP makes pessimistic assumption for entropy in session ID, probably because proving " | ||
+ | |||
+ | 10M active sessions are possible even with relatively small sites because there are users who use very long session ID life time for "auto login" | ||
+ | |||
+ | In addition to above, current session management implementation does not support timestamp based session data management. i.e. https:// | ||
+ | |||
+ | Somebody wins lottery. Even 1 in millions/ | ||
+ | |||
+ | If there are users who really do not want collision detection at all, they should do it by their own responsibility and risk. e.g. | ||
+ | |||
+ | <code php> | ||
+ | if (session_status() == PHP_SESSION_ACTIVE) { | ||
+ | session_commit(); | ||
+ | } | ||
+ | ini_set(' | ||
+ | // NIST requires SHA2 or better hash for collision sensitive usage. | ||
+ | $new_sid = hash(' | ||
+ | session_id($new_sid); | ||
+ | session_start() | ||
+ | </ | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
- | None. | + | None. Just a new function. |
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
- | PHP 7.1 | + | PHP 7.2 |
===== Voting Choices ===== | ===== Voting Choices ===== | ||
Line 79: | Line 197: | ||
* No | * No | ||
</ | </ | ||
+ | |||
+ | Vote starts: 2016/ | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 87: | Line 207: | ||
After the project is implemented, | After the project is implemented, | ||
- the version(s) it was merged to | - the version(s) it was merged to | ||
+ | - PHP 7.1 and master (Merged to 7.1 also by RM permission) | ||
- a link to the git commit(s) | - a link to the git commit(s) | ||
+ | - http:// | ||
- a link to the PHP manual entry for the feature | - a link to the PHP manual entry for the feature | ||
+ | - http:// | ||
===== References ===== | ===== References ===== |
rfc/session-create-id.1460159269.txt.gz · Last modified: 2017/09/22 13:28 (external edit)