[RFC][VOTE] Add session_create_id() function

php.internals

Yasuo Ohgaki

10 years ago
Hi all, This is RFC for adding session_create_id() function. Session ID string uses special binary to string conversion. Users should write lengthy and slow code to have the same session ID string as session module does. It also validates and makes sure generated session ID string has no collision. (This cannot be done easily by user script and 3rd party C written save handlers) https://wiki.php.net/rfc/session-create-id It requires 2/3 majority to pass. Vote starts: 2016/08/10 - Vote ends: 2016/08/17 23:59:59 UTC Thank you for voting!
-- Yasuo Ohgaki yohgaki@ohgaki.net

Marco Pivetta

10 years ago
Hello, The RFC mentions "Without session_create_id(), user has to implement their own bin_to_readable() in user land.". This pretty much makes it clear that a userland implementation is feasible, and thus it should indeed be implemented in userland when possible. That's my reasoning for voting "no". Cheers, Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/ On Wed, Aug 10, 2016 at 11:14 AM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:

Yasuo Ohgaki

10 years ago
Hi Marco, On Wed, Aug 10, 2016 at 6:31 PM, Marco Pivetta <ocramius@gmail.com> wrote:
> The RFC mentions "Without session_create_id(), user has to implement their > own bin_to_readable() in user land.". > This pretty much makes it clear that a userland implementation is feasible, > and thus it should indeed be implemented in userland when possible. > > That's my reasoning for voting "no".
Thank you for sharing your idea!
> This pretty much makes it clear that a userland implementation is feasible, > and thus it should indeed be implemented in userland when possible.
Actually, it's not with C written 3rd party session save handlers. Properly written save handlers should have internal s_validate_sid() function to check session ID collisions. User script cannot access to save handler internals. Therefore, it requires a lot of work if user try to create session ID properly. i.e. Validate generated session ID string does not collide. There is API design issue also. Let's say we add string str_bin2readble(string $binary, int $bis_per_char); then we need string str_reable2bin(string $readble_bin, int $bis_per_char); Internal bin_to_reable() function is not designed to reversible, i.e. It cannot convert $readable_bin to $binary, because it does not care trailing bits that cannot fit into a char. I need more info these function to be reversible. i.e. string str_reable2bin(string $readble_bin, int $bis_per_char, int $number_of_bits_in_readble_bin); These APIs do not look good to be usable... I hope I explained well the reason behind to have session_create_id(). Regards, P.S. I would like to change session_regenerate_id() accept 'prefix', but it has 1st parameter that I would like to remove in the future. This is the reason why I didn't change session_regenerate_id(). It requires a lot less user code session_rengenerate_id('myprefix-'); yet it is safe.
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
Hi all, On Wed, Aug 10, 2016 at 7:03 PM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> It requires a lot less user code > > session_rengenerate_id('myprefix-'); > > yet it is safe.
I forgot to mention important requirement. It is safe when 'session.use_strict_mode=1'. Unfortunately, RFC for enabling use_strict_mode by default https://wiki.php.net/rfc/session-use-strict-mode is declined.
-- Yasuo Ohgaki yohgaki@ohgaki.net

Leigh

10 years ago
On Wed, 10 Aug 2016 at 10:15 Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> Hi all, > > This is RFC for adding session_create_id() function. > > Session ID string uses special binary to string conversion. Users > should write lengthy and slow code to have the same session ID string > as session module does.
I disagree, this pretty much covers it: function session_create_id() { $encoded = base64_encode(random_bytes(32)); // Use same charset as PHP return rtrim(strtr($encoded, '+/', ',-'), '='); }

Yasuo Ohgaki

10 years ago
Hi Leigh, On Fri, Aug 12, 2016 at 3:25 AM, Leigh <leight@gmail.com> wrote:
> On Wed, 10 Aug 2016 at 10:15 Yasuo Ohgaki <yohgaki@ohgaki.net> wrote: >> >> Hi all, >> >> This is RFC for adding session_create_id() function. >> >> Session ID string uses special binary to string conversion. Users >> should write lengthy and slow code to have the same session ID string >> as session module does. > > > I disagree, this pretty much covers it: > > function session_create_id() > { > $encoded = base64_encode(random_bytes(random_bytes(32))); > // Use same charset as PHP > return rtrim(strtr($encoded, '+/', ',-'), '='); > }
Thank you for insight! You've missed to set SID to proper length and SID validation. function session_create_id(string $prefix) { $encoded = base64_encode(ini_get('session.sid_length')*2); // Use same charset as PHP $sid = substr(rtrim(strtr($encoded, '+/', ',-'), '='), 0, ini_get('session.sid_length'); $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 not there try again to generate SID few times if SID validation failed fatal error return safe SID when session is inactive return unvalidated SID } This is what proposed session_create_id() does. I used pseudo, but it should be easy to imagine it would be lengthy code. IMHO, mandatory API should be in PHP even if it's easy to implement and basic API should be in PHP unless it is too easy to be implemented userland. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
On Fri, Aug 12, 2016 at 7:58 AM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> if sid is not there
s/if sid is not there/if sid is there/
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
Hi Leigh, One more additional info. On Fri, Aug 12, 2016 at 7:58 AM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> IMHO, mandatory API should be in PHP even if it's easy to implement > and basic API should be in PHP unless it is too easy to be implemented > userland.
Session SID validation function should be mandatory for user defined save handlers. Unless we have ready to use session_create_id(), they have to implement by themselves. Requiring something like function session_create_id(string $prefix) { $encoded = base64_encode(ini_get('session.sid_length')*2); // Use same charset as PHP $sid = substr(rtrim(strtr($encoded, '+/', ',-'), '='), 0, ini_get('session.sid_length'); $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 } is not good API design, IMHO. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
Hi Leigh, On Fri, Aug 12, 2016 at 8:07 AM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> $encoded = base64_encode(ini_get('session.sid_length')*2); > // Use same charset as PHP > $sid = substr(rtrim(strtr($encoded, '+/', ',-'), '='), 0, > ini_get('session.sid_length');
I've missed to handle session.hash_bits_per_character here. There are people validating SID (used chars and length) via WAF or PHP code. session.hash_bits_per_character handling is mandatory for such system. Implementing things properly and precisely is not easy :) Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Lester Caine

10 years ago
On 12/08/16 00:20, Yasuo Ohgaki wrote:
> I've missed to handle session.hash_bits_per_character here. There are > people validating SID (used chars and length) via WAF or PHP code. > session.hash_bits_per_character handling is mandatory for such system.
Since 'id' is a variable, isn't this just a specialist constraint applied to that variable ;) The various new hash rules follow the same pattern. Add a domain of 'session_id' to the variable and that selects all the right rules to handle it ... yes specialist code generating a special variable may be more efficient, but if the framework is right than one can simply adjust the rules on a generic variable to cater for your own requirements?
-- Lester Caine - G8HFL ----------------------------- Contact - http://lsces.co.uk/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

Yasuo Ohgaki

10 years ago
Hi Lester, On Fri, Aug 12, 2016 at 5:01 PM, Lester Caine <lester@lsces.co.uk> wrote:
> On 12/08/16 00:20, Yasuo Ohgaki wrote: >> I've missed to handle session.hash_bits_per_character here. There are >> people validating SID (used chars and length) via WAF or PHP code. >> session.hash_bits_per_character handling is mandatory for such system. > > Since 'id' is a variable, isn't this just a specialist constraint > applied to that variable ;) The various new hash rules follow the same > pattern. Add a domain of 'session_id' to the variable and that selects > all the right rules to handle it ... yes specialist code generating a > special variable may be more efficient, but if the framework is right > than one can simply adjust the rules on a generic variable to cater for > your own requirements?
I don't think it's framework job to do. See "User land session_create_id() is easy" section. https://wiki.php.net/rfc/session-create-id#discussions It's not easy nor task for frameworks. If framework would like to write session_create_id() "properly", framework must access session storage database. Let's say storage is memcached, then framework must open memcached connection by itself and perform session ID validation. Let's say storage is PostgreSQL, then framework must open... the same for every other C written session save handler. Clearly, it's not a task for framework, but session module. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Lester Caine

10 years ago
On 12/08/16 09:23, Yasuo Ohgaki wrote:
> I don't think it's framework job to do.
This was a little 'tongue in cheek' ... my main thought was simply that you need a variable 'session_id' and other processes may benefit from a similarly constrained variable, so an intelligent variable could be envisaged that has the code for creating that value. In any case if the session code creates the variable, you want to ensure that nothing else modifies it, so $session_id variable should be read_only and blocked from accidentally escaping it, so even though it is generated within the session code it's result needs to follow some rules.
-- Lester Caine - G8HFL ----------------------------- Contact - http://lsces.co.uk/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

Yasuo Ohgaki

10 years ago
Hi Lester, On Fri, Aug 12, 2016 at 6:12 PM, Lester Caine <lester@lsces.co.uk> wrote:
> On 12/08/16 09:23, Yasuo Ohgaki wrote: >> I don't think it's framework job to do. > > This was a little 'tongue in cheek' ... my main thought was simply that > you need a variable 'session_id' and other processes may benefit from a > similarly constrained variable, so an intelligent variable could be > envisaged that has the code for creating that value. In any case if the > session code creates the variable, you want to ensure that nothing else > modifies it, so $session_id variable should be read_only and blocked > from accidentally escaping it, so even though it is generated within the > session code it's result needs to follow some rules.
I see. I think it's good to have intelligent scalar if costs/overheads are little. Anyway, thank you for the comment. There may be people that thinks session_create_id() should be a part of framework or user code. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Lester Caine

10 years ago
On 12/08/16 10:22, Yasuo Ohgaki wrote:
> Hi Lester, > > On Fri, Aug 12, 2016 at 6:12 PM, Lester Caine <lester@lsces.co.uk> wrote: >> On 12/08/16 09:23, Yasuo Ohgaki wrote: >>> I don't think it's framework job to do. >> >> This was a little 'tongue in cheek' ... my main thought was simply that >> you need a variable 'session_id' and other processes may benefit from a >> similarly constrained variable, so an intelligent variable could be >> envisaged that has the code for creating that value. In any case if the >> session code creates the variable, you want to ensure that nothing else >> modifies it, so $session_id variable should be read_only and blocked >> from accidentally escaping it, so even though it is generated within the >> session code it's result needs to follow some rules. > > I see. I think it's good to have intelligent scalar if costs/overheads > are little. > > Anyway, thank you for the comment. There may be people that thinks > session_create_id() should be a part of framework or user code.
We are probably on the same sheet. I'd prefer to restore the ADOdb extension that handled time sensitive code in C but that has not kept pace with all the other changes to extensions. Everything can be done in user space but just what would benefit from optimising in C.
-- Lester Caine - G8HFL ----------------------------- Contact - http://lsces.co.uk/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

Tom Worster

10 years ago
On 8/11/16 6:58 PM, Yasuo Ohgaki wrote:
> Hi Leigh, > > On Fri, Aug 12, 2016 at 3:25 AM, Leigh <leight@gmail.com> wrote: >> On Wed, 10 Aug 2016 at 10:15 Yasuo Ohgaki <yohgaki@ohgaki.net> wrote: >>> >>> Hi all, >>> >>> This is RFC for adding session_create_id() function. >>> >>> Session ID string uses special binary to string conversion. Users >>> should write lengthy and slow code to have the same session ID string >>> as session module does. >> >> >> I disagree, this pretty much covers it: >> >> function session_create_id() >> { >> $encoded = base64_encode(random_bytes(random_bytes(32))); >> // Use same charset as PHP >> return rtrim(strtr($encoded, '+/', ',-'), '='); >> } > > Thank you for insight! > > You've missed to set SID to proper length and SID validation.
Replacing rtrim() with substr() is fixes that.
> function session_create_id(string $prefix) > { > $encoded = base64_encode(ini_get('session.sid_length')*2);
Did you omit random_bytes() in this line?
> // Use same charset as PHP > $sid = substr(rtrim(strtr($encoded, '+/', ',-'), '='), 0, > ini_get('session.sid_length'); > > $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 not there > try again to generate SID few times > if SID validation failed > fatal error > return safe SID > when session is inactive > return unvalidated SID > } > > This is what proposed session_create_id() does. > I used pseudo, but it should be easy to imagine it would be lengthy code.
You don't need to waste time checking for collisions if the SID has a random component of sufficient length. 32 random base-64 characters is sufficient. There are lots of purposes for random strings with negligible chance of collision. Hence some frameworks provide the function, e.g. http://www.yiiframework.com/doc-2.0/yii-base-security.html#generateRandomString()-detail Only the search of the the session database for collisions seems hard to me. But I don't understand why it is needed. Tom

Yasuo Ohgaki

10 years ago
Hi Tom, On Sat, Aug 13, 2016 at 3:11 AM, Tom Worster <fsb@thefsb.org> wrote:
> On 8/11/16 6:58 PM, Yasuo Ohgaki wrote: >> >> Hi Leigh, >> >> On Fri, Aug 12, 2016 at 3:25 AM, Leigh <leight@gmail.com> wrote: >>> >>> On Wed, 10 Aug 2016 at 10:15 Yasuo Ohgaki <yohgaki@ohgaki.net> wrote: >>>> >>>> >>>> Hi all, >>>> >>>> This is RFC for adding session_create_id() function. >>>> >>>> Session ID string uses special binary to string conversion. Users >>>> should write lengthy and slow code to have the same session ID string >>>> as session module does. >>> >>> >>> >>> I disagree, this pretty much covers it: >>> >>> function session_create_id() >>> { >>> $encoded = base64_encode(random_bytes(random_bytes(32))); >>> // Use same charset as PHP >>> return rtrim(strtr($encoded, '+/', ',-'), '='); >>> } >> >> >> Thank you for insight! >> >> You've missed to set SID to proper length and SID validation. > > > Replacing rtrim() with substr() is fixes that.
No. Base 64 adds padding for extra bytes. The Padding char is "=" and it's illegal char as SID. Therefore trims is mandatory. Don't you think it's nice to make "PHP just works" without knowing such details?
> > >> function session_create_id(string $prefix) >> { >> $encoded = base64_encode(ini_get('session.sid_length')*2); > > > Did you omit random_bytes() in this line?
I don't why I did this :) I thought I replaced "32" to ini setting.
> > >> // Use same charset as PHP >> $sid = substr(rtrim(strtr($encoded, '+/', ',-'), '='), 0, >> ini_get('session.sid_length'); >> >> $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 not there >> try again to generate SID few times >> if SID validation failed >> fatal error >> return safe SID >> when session is inactive >> return unvalidated SID >> } >> >> This is what proposed session_create_id() does. >> I used pseudo, but it should be easy to imagine it would be lengthy code. > > > You don't need to waste time checking for collisions if the SID has a random > component of sufficient length. 32 random base-64 characters is sufficient. > > There are lots of purposes for random strings with negligible chance of > collision. Hence some frameworks provide the function, e.g. > http://www.yiiframework.com/doc-2.0/yii-base-security.html#generateRandomString()-detail > > Only the search of the the session database for collisions seems hard to me. > But I don't understand why it is needed.
Session ID security is key factor of Web application security. There is huge difference between 'cannot happen' and 'very rare and almost cannot happen'. In addition, proving 'very rare and almost cannot happen' is difficult. NIST requires SHA2 or better hash for collision sensitive usage. SHA2 has 256 bits or more. We only use 128 bits, i.e. MD5 and bits_per_character=5 now. (130 bits for 7.1 and later). Therefore, I don't think collision check is needless. We should have 256 bits session ID at least which requires 52 chars with 5 bits_per_character. We know it's relatively easy to check if a PRNG meets NIST requirement, but requirement fulfillment does not mean PRNG is generating excellent random. Measuring quality of PRNG is difficult. (This does not mean we should add low quality entropy such as time and pid to create SID and hash it. We depends on PRNG security anyway, use of hash and low quality entropy only makes SID weaker. Thus I proposed raw PRNG usage for SID) These things make me think collision detection is mandatory to say "PHP session is secure". Anyway, I'm not a cryptographer and just following their advices. I suggest you do the same. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Tom Worster

10 years ago
Hi Yasu, On 8/12/16, 4:38 PM, "Yasuo Ohgaki" <yohgaki@ohgaki.net> wrote:
>Base 64 adds padding for extra bytes. The Padding char is "=" and it's >illegal char as SID. Therefore trims is mandatory.
substr(base64_encode(random_bytes($n)), 0, $n). There is no "=" in the value for any $n.
>Don't you think it's nice to make "PHP just works" without knowing such >details?
Not in this particular instance, no. Anybody that takes on the responsibility of designing a scheme for session ID generation needs to know such details. The typical PHP programmer does/should not do such work because its is difficult and dangerous and because the requirement seldom arises. PHP should not try to patch up garbage session IDs by rejecting IDs already in use.
>Session ID security is key factor of Web application security. There >is huge difference between 'cannot happen' and 'very rare and almost >cannot happen'. In addition, proving 'very rare and almost cannot >happen' is difficult.
This is equivalent to saying that random_bytes() cannot be trusted as a CSPRNG.
>NIST requires SHA2 or better hash for collision sensitive usage. SHA2 >has 256 bits or more. We only use 128 bits, i.e. MD5 and >bits_per_character=5 now. (130 bits for 7.1 and later).
Hashing is not the same problem. It's different in some important ways.
>Therefore, I >don't think collision check is needless. We should have 256 bits >session ID at least which requires 52 chars with 5 bits_per_character.
I don't think NIST's hashing recommendations should be the basis for saying how many random bits PHP session IDs should have. I think we should make our own calculations from first principles.
>We know it's relatively easy to check if a PRNG meets NIST >requirement, but requirement fulfillment does not mean PRNG is >generating excellent random. Measuring quality of PRNG is difficult. >(This does not mean we should add low quality entropy such as time and >pid to create SID and hash it. We depends on PRNG security anyway, use >of hash and low quality entropy only makes SID weaker. Thus I proposed >raw PRNG usage for SID)
Since 7.0, PHP uses the best available practices to obtain random bytes from the operating system's CSPRNG. These practices are generally considered good enough for strong cryptography, which demands as much from a CSPRNG as PHP sessions. It doesn't make sense to distrust random_bytes() but at the same time trust the host PHP runs on.
>These things make me think collision detection is mandatory to say >"PHP session is secure". > >Anyway, I'm not a cryptographer and just following their advices. I >suggest you do the same.
I don't agree with the conclusions you draw from NIST hashing recommendations. Tom

Yasuo Ohgaki

10 years ago
Hi Tom, On Sun, Aug 14, 2016 at 12:22 AM, Tom Worster <fsb@thefsb.org> wrote:
> On 8/12/16, 4:38 PM, "Yasuo Ohgaki" <yohgaki@ohgaki.net> wrote: > >>Base 64 adds padding for extra bytes. The Padding char is "=" and it's >>illegal char as SID. Therefore trims is mandatory. > > substr(base64_encode(random_bytes($n)), 0, $n). There is no "=" in the > value for any $n.
Generally speaking, you should consider "=" padding when you use Base64 encoding. Refer to https://tools.ietf.org/html/rfc4648#section-8 and relevant sections.
> > >>Don't you think it's nice to make "PHP just works" without knowing such >>details? > > Not in this particular instance, no. Anybody that takes on the > responsibility of designing a scheme for session ID generation needs to > know such details. The typical PHP programmer does/should not do such work > because its is difficult and dangerous and because the requirement seldom > arises. PHP should not try to patch up garbage session IDs by rejecting > IDs already in use.
My point of view is "session" (the connection/request state management) should "just work" without knowing details. My recent session related proposals accomplish this objective. IMO. PHP should be easiest, yet secure, Web application programming language. I don't see any benefits, but only drawbacks, forcing users "to know session management details to write secure code" while it is very easy to implement tham in Session module.
> > >>Session ID security is key factor of Web application security. There >>is huge difference between 'cannot happen' and 'very rare and almost >>cannot happen'. In addition, proving 'very rare and almost cannot >>happen' is difficult. > > This is equivalent to saying that random_bytes() cannot be trusted as a > CSPRNG.
No. It means we should be careful about CSPRNG randomness. Therefore, I validate SID.
> > >>NIST requires SHA2 or better hash for collision sensitive usage. SHA2 >>has 256 bits or more. We only use 128 bits, i.e. MD5 and >>bits_per_character=5 now. (130 bits for 7.1 and later). > > Hashing is not the same problem. It's different in some important ways.
I'm reading between the line here. Cryptographers considers hash less 256 bits is not longer secure. They think 256 bits or more to avoid collisions. As you may know, CSPRNGs use hashes internally. This fact makes me think we shouldn't blindly trust CSPRNG return values less than 256bits.
> > > >>Therefore, I >>don't think collision check is needless. We should have 256 bits >>session ID at least which requires 52 chars with 5 bits_per_character. > > I don't think NIST's hashing recommendations should be the basis for > saying how many random bits PHP session IDs should have. I think we should > make our own calculations from first principles.
If you would like to know how many bits (true random bits) required for secure session ID. Following link is helpful to figure out some aspect of session ID security. https://www.owasp.org/index.php/Insufficient_Session-ID_Length We use 130bits out of CSPRNG radam for PHP 7.1. How many bytes is required for secure session ID is depends on CSPRNG quality and measuring CSPRNG quality is difficult. To avoid collision, all we have to do is validating SID then problem is solved. (Predictability is different issue)
> >>We know it's relatively easy to check if a PRNG meets NIST >>requirement, but requirement fulfillment does not mean PRNG is >>generating excellent random. Measuring quality of PRNG is difficult. >>(This does not mean we should add low quality entropy such as time and >>pid to create SID and hash it. We depends on PRNG security anyway, use >>of hash and low quality entropy only makes SID weaker. Thus I proposed >>raw PRNG usage for SID) > > Since 7.0, PHP uses the best available practices to obtain random bytes > from the operating system's CSPRNG. These practices are generally > considered good enough for strong cryptography, which demands as much from > a CSPRNG as PHP sessions. > > It doesn't make sense to distrust random_bytes() but at the same time > trust the host PHP runs on.
Even serious cryptographers admits difficulty of CSPRNG quality assurance. We cannot force OSes to have excellent CSPRNG that will never have collision for obtained bytes.
> > >>These things make me think collision detection is mandatory to say >>"PHP session is secure". >> >>Anyway, I'm not a cryptographer and just following their advices. I >>suggest you do the same. > > I don't agree with the conclusions you draw from NIST hashing > recommendations.
My proposal is much secure than your proposal. It is clear by logic described above that my proposal is more secure. Anyway, if things can done easily by PHP, if it is related to security and if users can forget about secureness when they stick to normal PHP usage, PHP should be provided as default feature. Let user mustn't know session security details! I think this is the way PHP should go. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Lester Caine

10 years ago
On 14/08/16 01:56, Yasuo Ohgaki wrote:
> IMO. PHP should be easiest, yet secure, Web application programming language. > I don't see any benefits, but only drawbacks, forcing users "to know session > management details to write secure code" while it is very easy to implement > tham in Session module.
Sessions are something I rely on, but have thrown numerous problems over the years. In my systems they should exist for the duration of a client being logged into the system and so any problems either end have to be handled. For that reason I store them in the database so when a client has to log in again we can clear their last activity and start a new one. The clients can be carrying out interviews for an hour or more, so previous 'improvements' that try to clear 'inactive sessions' often lost MY sort of sessions. Clients are only allowed to log on once so I need to pick up if they try and start a second session, but I don't believe I NEED all the complexity of cryptography secure id's? Just ones where I CAN actually identify the client ... or should I be handling that separate from the actual session_id ?
-- Lester Caine - G8HFL ----------------------------- Contact - http://lsces.co.uk/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

Yasuo Ohgaki

10 years ago
Hi Lester, On Sun, Aug 14, 2016 at 5:35 PM, Lester Caine <lester@lsces.co.uk> wrote:
> On 14/08/16 01:56, Yasuo Ohgaki wrote: >> IMO. PHP should be easiest, yet secure, Web application programming language. >> I don't see any benefits, but only drawbacks, forcing users "to know session >> management details to write secure code" while it is very easy to implement >> tham in Session module. > > Sessions are something I rely on, but have thrown numerous problems over > the years. In my systems they should exist for the duration of a client > being logged into the system and so any problems either end have to be > handled. For that reason I store them in the database so when a client > has to log in again we can clear their last activity and start a new > one. The clients can be carrying out interviews for an hour or more, so > previous 'improvements' that try to clear 'inactive sessions' often lost > MY sort of sessions. Clients are only allowed to log on once so I need > to pick up if they try and start a second session, but I don't believe I > NEED all the complexity of cryptography secure id's? Just ones where I > CAN actually identify the client ... or should I be handling that > separate from the actual session_id ?
Concept of Session is simple just like transaction. Concept of transaction is simple but implementation requires complexity to do the job right. You wouldn't say 'Transaction could be inconsistent under rare unfortunate situations' probably. Anyway, session module generates collision free session ID by default. Why not for API generates new ID? Collision check for new session ID is cheap because it does not happen for every request, but only when session ID is regenerated. In addition, user needs a lot of work and details of session, including session save handler knowledge to generate collision free session ID. If anyone would really like to remove collision check overhead, they should do it by themselves. Unlike collision free session ID generation, it's very easy. Users can do ini_set('session.use_strict_mode', 0); session_id('my_session_id'); session_start(); with their own responsibility and risk. Regards, P.S. The next step having session_create_id() is session_regenerate_id() change. For example, having user ID prefixed session would be just session_regenerate_id(session_create_id($userid)); Warning: To do things like this safely, user MUST enable use_strict_mode!!
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
Hi all, It seems importance of session ID validation that prevents collisions is not recognized enough. Brute force session ID hihack risk is described here. https://www.owasp.org/index.php/Insufficient_Session-ID_Length The expected number of seconds required to guess a valid session identifier is given by the equation: (2^B+1)/(2*A*S) 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 "Now assume a 128 bit session identifier that provides 64 bits of entropy. With a very large web site, an attacker might try 10,000 guesses per second with 100,000 valid session identifiers available to be guessed. Given these assumptions, the expected time for an attacker to successfully guess a valid session identifier is greater than 292 years." 292 years may sounds long enough. However, even though the document explicitly states "it requires validated session ID", but it is clear it assumes "session manager that validates session ID". Let me paraphrase OWASP's document to show why. "Now assume a 128 bit session identifier that provides 64 bits of entropy. With a very large web site, legitimate users might creates 10,000 new session ID per second (New and regenerated session) with 10,000,000 valid session identifiers available to be collided. Given these assumptions, the expected time web system to successfully has collided identifier is greater than 2 years." Assumption for security should be pessimistic. OWASP makes pessimistic assumption for entropy in session ID, probably because proving "CSPRNG generates good quality of random bytes" is difficult. 10M active session is possible even with relatively small sites because there are users who use very long session ID life time for "auto login". 10K new session ID is possible for relatively small sites also because OWASP recommends session ID regeneration for every 15 minutes. IMHO, it's nonsense to argue "Session ID collision very rare and cannot happen", "PHP Session ID safe without collision detection", etc. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Yasuo Ohgaki

10 years ago
Hi all, On Wed, Aug 10, 2016 at 6:14 PM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> This is RFC for adding session_create_id() function. > > Session ID string uses special binary to string conversion. Users > should write lengthy and slow code to have the same session ID string > as session module does. It also validates and makes sure generated > session ID string has no collision. (This cannot be done easily by > user script and 3rd party C written save handlers) > > https://wiki.php.net/rfc/session-create-id > It requires 2/3 majority to pass. > Vote starts: 2016/08/10 - Vote ends: 2016/08/17 23:59:59 UTC
I've added discussion section so that new readers do not have to read thread. https://wiki.php.net/rfc/session-create-id#discussions Those who are not feeling session_create_id() function might not be needed, please try to write session ID validation enabled (NOTE: Session ID validation is **mandatory** for session security) user defined session save handler. Then you'll see why. Not many people voted yet, but this function is "missing must have API". Thank you for voting! https://wiki.php.net/rfc/session-create-id Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Tom Worster

10 years ago
On 8/10/16 5:14 AM, Yasuo Ohgaki wrote:
> Hi all, > > This is RFC for adding session_create_id() function. > > Session ID string uses special binary to string conversion. Users > should write lengthy and slow code to have the same session ID string > as session module does. It also validates and makes sure generated > session ID string has no collision. (This cannot be done easily by > user script and 3rd party C written save handlers)
Rather than argue the details of randomness, I have more basic comments. 1. If an app needs to access session values, it can and should do this without indirection through the PHP session ID table. 2. Users should generally let PHP choose random IDs. 3. If PHP is to allow a user to chose its own session IDs, avoiding collision is should that user's responsibility. 4. Generating unique unpredictable IDs (without requiring collision detection) is a common problem with known and trusted solutions. Tom

Yasuo Ohgaki

10 years ago
Hi Tom, On Sun, Aug 14, 2016 at 12:35 AM, Tom Worster <fsb@thefsb.org> wrote:
> Rather than argue the details of randomness, I have more basic comments. > > 1. If an app needs to access session values, it can and should do this > without indirection through the PHP session ID table.
I don't get point. Why?
> > 2. Users should generally let PHP choose random IDs.
I agree.
> > 3. If PHP is to allow a user to chose its own session IDs, avoiding > collision is should that user's responsibility.
No. I've already explained why this is difficult. Please read previous mail. Or try to write session save handler that detects collisions with memcached, then you'll see why.
> > 4. Generating unique unpredictable IDs (without requiring collision > detection) is a common problem with known and trusted solutions.
I agree. It's common because many unique ID generator do not have centralized database to avoid collisions. In contract, session has centralized database and it's just a matter of one lookup. (Therefore, session module should lookup database) Regards, P.S. I'll add optimization that eliminates SID validation lookup for normal operations. You don't have to worry about session performance if I add this.
-- Yasuo Ohgaki yohgaki@ohgaki.net

Tom Worster

10 years ago
On 8/13/16 9:02 PM, Yasuo Ohgaki wrote:
> Hi Tom, > > On Sun, Aug 14, 2016 at 12:35 AM, Tom Worster <fsb@thefsb.org> wrote: >> Rather than argue the details of randomness, I have more basic comments. >> >> 1. If an app needs to access session values, it can and should do this >> without indirection through the PHP session ID table. > > I don't get point. Why?
1) It is not necessary. An app can instead store session-related data in a DB that provides lookup and/or search on the session data itself rather than the PHP session key. Lester Caine described this. 2) Searching PHP's session database is nasty. It's low-level and the app has to understand the handler. But I want apps to work independent of sessions being in memcache to Redis or Galera or whatever. Depending on handler, it can involve a scan which is slow. And it's hard to make the overall operation that uses session table lookup transnational. And the session store may be distributed example below(*). So it's nasty **and** unnecessary. Instead, the app can and should implement the business logic to be entirely above and ignorant of PHP session mechanics.
>> 2. Users should generally let PHP choose random IDs. > > I agree. > >> >> 3. If PHP is to allow a user to chose its own session IDs, avoiding >> collision is should that user's responsibility. > > No. I've already explained why this is difficult.
It is easy if you choose to **avoid** rather than **detect**. Use a random component long enough for your needs. In other words, I disagree with the sentence in your RFC:
> Something like above code is required to implement recommended user
session save handlers currently. It is not needed because if 64^32 SID values is inadequate for your app then you may increase session.sid_length.
> Please read previous mail. > Or try to write session save handler that detects collisions with > memcached, then you'll see why.
I understand your point. At the same time I see no need for collision detection. Questions: When I get a value from session_create_id(), what kind of guarantee comes with it? Is the ID reserved for me? If so, for how long?
>> 4. Generating unique unpredictable IDs (without requiring collision >> detection) is a common problem with known and trusted solutions. > > I agree. It's common because many unique ID generator do not have > centralized database to avoid collisions. In contract, session has > centralized database and it's just a matter of one lookup. (Therefore, > session module should lookup database)
(*)Some session stores are federated, e.g. a cluster of 3 hosts each with a memcached server and each with PHP configured with session redundancy to save two copies. While session_create_id() could potentially use the same hashes that memcache/d extensions uses to associate SIDs with memcached servers, the app has to search them to find the entry with a given SID prefix.

Yasuo Ohgaki

10 years ago
Hi all, On Wed, Aug 10, 2016 at 6:14 PM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> https://wiki.php.net/rfc/session-create-id > It requires 2/3 majority to pass. > Vote starts: 2016/08/10 - Vote ends: 2016/08/17 23:59:59 UTC
There are 2 mistakes in pseudo example code in discussion section and fixed - add missing random_bytes() - fix wrong logic (if sid is not there -> if sid is there) Sorry for sloppy example! Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Pascal MARTIN

10 years ago
Le 10/08/2016 à 11:14, Yasuo Ohgaki a écrit :
> Hi all, > > This is RFC for adding session_create_id() function.
Hi again, Not that many of us at AFUP discussed about this RFC (maybe it's because of the summer and holidays, or it's because not many of us need this?), but those who did all agree having such a function provided by PHP will be better than trying to implement it ourselves, the day it's actually needed -- and it's a single function without much impact or bc-break anywhere else. So, we would be +1. Thanks again for your work on this!
-- Pascal MARTIN, AFUP - French UG http://php-internals.afup.org/

Yasuo Ohgaki

10 years ago
Hi all, On Wed, Aug 10, 2016 at 6:14 PM, Yasuo Ohgaki <yohgaki@ohgaki.net> wrote:
> > This is RFC for adding session_create_id() function. > > Session ID string uses special binary to string conversion. Users > should write lengthy and slow code to have the same session ID string > as session module does. It also validates and makes sure generated > session ID string has no collision. (This cannot be done easily by > user script and 3rd party C written save handlers) > > https://wiki.php.net/rfc/session-create-id > It requires 2/3 majority to pass. > Vote starts: 2016/08/10 - Vote ends: 2016/08/17 23:59:59 UTC > > Thank you for voting!
Sorry for the delay. This RFC has passed by 8 vs 1. Thank you for voting! I'll merge patch and write document soon. Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net