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
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
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 UTCThank you for voting!
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi Marco,
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
Hi all,
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
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, '+/', ',-'), '=');
}
Hi Leigh,
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
Hi Leigh,
One more additional info.
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
Hi Leigh,
$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
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
Hi Lester,
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
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
Hi Lester,
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
Hi Lester,
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
Hi Leigh,
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
Hi Tom,
Hi Leigh,
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()
withsubstr()
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()-detailOnly 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
Hi Yasu,
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
Hi Tom,
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
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
Hi Lester,
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
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)/(2AS)
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
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.
I forgot to mention that "Session management without timestamp will situation
worse" because session_regenerate_id()
creates many active sessions by default.
(Please refer to decline RFC timestamp managed session
https://wiki.php.net/rfc/precise_session_management )
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Hi all,
"The default 128 bits Session ID is large enough to ignore collisions"
discussion is added for new readers and people couldn't follow
discussion in ML threads.
https://wiki.php.net/rfc/session-create-id#discussions
For the record, when session module was implemented, the way it is now
is considered good enough for most users. Circumstances change as time
goes by.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
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_LengthThe expected number of seconds required to guess a valid session
identifier is given by the equation:(2^B+1)/(2AS)
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 timeIt 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
"Now assume a 128 bit session identifier that provides 64 bits of
entropy.
What exactly does this mean?
If it means that an attacker knows how to eliminate 2^128 - 2^64
impossible SID values from a search then that SID generation is
insecure, dangerous garbage. (This isn't the only statement I've seen on
OWASP that strikes me as very odd.)
Each bit of output from a CSPRNG such as random_bytes()
is equally and
independently unpredictable. Hence a brute force attack cannot know that
some values are not in its output and may therefore be skipped in a search.
There are 64^32 = 2^192 ~= 6.3e+57 different 32-bytes base-64 string
values. If a session DB has 1e+7 such SIDs chosen at random then each
blind insertion/trial has ~1 in 6.3e+50 chance of a hit. At 1e+4
trials/sec the chance of a hit is ~1 in 6.3e+46 in one second. The age
of planet Earth is ~1.4e+17 seconds.
Your calculation (I assume based on that sentence from OWASP) has
128-bit SIDs of which only half are unpredictable. So there are 2^64 ~=
1.8e+19 different SIDs and (at 10e+4 trials/sec on a DB of 1e+7 SIDs)
the chance of a hit in one second is ~1.8e+8, which is obviously
insufficient.
But so what? Four-letter passwords are obviously insufficient too. The
calculation doesn't support the conclusion...
IMHO, it's nonsense to argue "Session ID collision very rare and
cannot happen", "PHP Session ID safe without collision detection",
etc.
If random SIDs math is nonsense that cannot be trusted then it is
because either the a) CSPRNG or b) code deriving SIDs from it is
dangerous garbage.
Either way its the dangerous garbage that should be fixed. Nobody should
just accept such disgraceful SID generation and patch it up with
collision detection.
Tom
"Now assume a 128 bit session identifier that provides 64 bits of
entropy.What exactly does this mean?
When you have random 128 bits value, it does not mean it has full size entropy.
Anyway, why you insist? CSPRNG should be good enough for security
purpose, but nobody proves CSPRNG that PHP uses are collision free.
Session ID validation is cheap cost for serious web users.
Basically you're saying “We do know it may happen, but you just had
rare bad luck. Even though protection could be implemented, whatever
consequences are your responsibility. It's the PHP way”.
I strongly disagree with this kind of attitude.
If there are users who really do not want collision detection at all,
they should do it by their own responsibility and risk.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
"Now assume a 128 bit session identifier that provides 64 bits of
entropy.What exactly does this mean?
When you have random 128 bits value, it does not mean it has full size entropy.
Anyway, why you insist? CSPRNG should be good enough for security
purpose, but nobody proves CSPRNG that PHP uses are collision free.
Session ID validation is cheap cost for serious web users.Basically you're saying “We do know it may happen, but you just had
rare bad luck. Even though protection could be implemented, whatever
consequences are your responsibility. It's the PHP way”.
I strongly disagree with this kind of attitude.If there are users who really do not want collision detection at all,
they should do it by their own responsibility and risk.
Above discussion is added to the RFC.
The default 128 bits Session ID is large enough to ignore collisions
https://wiki.php.net/rfc/session-create-id#discussions
It describes for an application, but PHP is a platform.
There are millions PHP apps or more and there could be billions of
active sessions. There could be tens of thousands new session IDs or
more are created. Apply the calculation for expected time of possible
collision.
Do you still sure "There will be no collisions at all"?
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
Do you still sure "There will be no collisions at all"?
Do you still think it's sure "There will be no collisions at all"?
--
Yasuo Ohgaki
yohgaki@ohgaki.net
"Now assume a 128 bit session identifier that provides 64 bits of
entropy.What exactly does this mean?
When you have random 128 bits value, it does not mean it has full size
entropy.Anyway, why you insist? CSPRNG should be good enough for security
purpose, but nobody proves CSPRNG that PHP uses are collision free.
Session ID validation is cheap cost for serious web users.Basically you're saying “We do know it may happen, but you just had
rare bad luck. Even though protection could be implemented, whatever
consequences are your responsibility. It's the PHP way”.
That is not what I am basically saying.
I strongly disagree with this kind of attitude.
If there are users who really do not want collision detection at all,
they should do it by their own responsibility and risk.Above discussion is added to the RFC.
The default 128 bits Session ID is large enough to ignore collisions
https://wiki.php.net/rfc/session-create-id#discussionsIt describes for an application, but PHP is a platform.
There are millions PHP apps or more and there could be billions of
active sessions. There could be tens of thousands new session IDs or
more are created. Apply the calculation for expected time of possible
collision.Do you still sure "There will be no collisions at all"?
The calculation underestimates the difficulty of finding collisions by 38
decimal orders of magnitude. The number of different SIDs in default PHP
config is 2^192, not 2^64. So yes, I am still sure.
Tom
The default 128 bits Session ID is large enough to ignore collisions
https://wiki.php.net/rfc/session-create-id#discussionsIt describes for an application, but PHP is a platform.
There are millions PHP apps or more and there could be billions of
active sessions. There could be tens of thousands new session IDs or
more are created. Apply the calculation for expected time of possible
collision.Do you still sure "There will be no collisions at all"?
The calculation underestimates the difficulty of finding collisions by 38
decimal orders of magnitude. The number of different SIDs in default PHP
config is 2^192, not 2^64. So yes, I am still sure.
In a distributed system which would be required to handle millions of
sessions at the same time, then one will have thousands of copies of PHP
running and shared via some sort of traffic manager. So unless some sort
of mechanism is included to provide identification of the PHP instance
then it is probable that different instances will all produce the same
sequence of numbers. A UUID generator provided to ensure every
distributed service has a uniquely identifiable id for every 'session'
is not something that forms part of a single instance of PHP. It must be
centrally managed with a central session store. All that a single
instance of PHP should be worrying about is a few hundred active sessions?
--
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
Hi Lester,
The default 128 bits Session ID is large enough to ignore collisions
https://wiki.php.net/rfc/session-create-id#discussionsIt describes for an application, but PHP is a platform.
There are millions PHP apps or more and there could be billions of
active sessions. There could be tens of thousands new session IDs or
more are created. Apply the calculation for expected time of possible
collision.Do you still sure "There will be no collisions at all"?
The calculation underestimates the difficulty of finding collisions by 38
decimal orders of magnitude. The number of different SIDs in default PHP
config is 2^192, not 2^64. So yes, I am still sure.In a distributed system which would be required to handle millions of
sessions at the same time, then one will have thousands of copies of PHP
running and shared via some sort of traffic manager. So unless some sort
of mechanism is included to provide identification of the PHP instance
then it is probable that different instances will all produce the same
sequence of numbers. A UUID generator provided to ensure every
distributed service has a uniquely identifiable id for every 'session'
is not something that forms part of a single instance of PHP. It must be
centrally managed with a central session store. All that a single
instance of PHP should be worrying about is a few hundred active sessions?
For most PHP applications does not have to worry much as it would be
extremely rare. i.e. Application users shouldn't worry much, or even at all.
However, we are developers who are dealing with "authentication" related issue.
Developers should make sure 120% correctness of authentication whenever
it is possible.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
The default 128 bits Session ID is large enough to ignore collisions
https://wiki.php.net/rfc/session-create-id#discussionsIt describes for an application, but PHP is a platform.
There are millions PHP apps or more and there could be billions of
active sessions. There could be tens of thousands new session IDs or
more are created. Apply the calculation for expected time of possible
collision.Do you still sure "There will be no collisions at all"?
The calculation underestimates the difficulty of finding collisions by 38
decimal orders of magnitude. The number of different SIDs in default PHP
config is 2^192, not 2^64. So yes, I am still sure.In a distributed system which would be required to handle millions of
sessions at the same time, then one will have thousands of copies of PHP
running and shared via some sort of traffic manager. So unless some sort
of mechanism is included to provide identification of the PHP instance
then it is probable that different instances will all produce the same
sequence of numbers. A UUID generator provided to ensure every
distributed service has a uniquely identifiable id for every 'session'
is not something that forms part of a single instance of PHP. It must be
centrally managed with a central session store. All that a single
instance of PHP should be worrying about is a few hundred active sessions?
(I think you could use a hash for this. But that's beside the point
because...)
I have no problem with session_create_id()
.
I have a problem with saying that CSPRNG is so untrustworthy that users
must find ways to compensate for its faults in their code.
And I have a problem with a statement to this effect being in the RFC.
And with that statement obscuring the crux of the argument with
misleading math about an SID database.
Tom
Hi Tom,
I strongly disagree with this kind of attitude.
If there are users who really do not want collision detection at all,
they should do it by their own responsibility and risk.Above discussion is added to the RFC.
The default 128 bits Session ID is large enough to ignore collisions
https://wiki.php.net/rfc/session-create-id#discussionsIt describes for an application, but PHP is a platform.
There are millions PHP apps or more and there could be billions of
active sessions. There could be tens of thousands new session IDs or
more are created. Apply the calculation for expected time of possible
collision.Do you still sure "There will be no collisions at all"?
The calculation underestimates the difficulty of finding collisions by 38
decimal orders of magnitude. The number of different SIDs in default PHP
config is 2^192, not 2^64. So yes, I am still sure.
In theory, there wouldn't be collisions if CSPRNG is truly random that
will never has collided values at any given chunks. 128 bits session ID
would be far good enough.
Problem is we can measure CSPRNG is producing acceptable random
for apps requires randomness, but it is difficult making sure the random
stream will never has collision.
(I'm not saying CSPRNG is not generating secure random. For most
usages of random stream do not require uniqueness. Session
module is special and requires collision free results for all CSPRNG.)
Solution is simple for session database. All we have to do is validating
newly generated session ID would not collide existing one. This is done
by session module currently. Why not for new API that is supposed to
generate 120% secure session ID?
If users do not want 120% secure session ID, but almost 100% secure
session ID is enough and would like to skip the validation. They may do
if (session_ status() == PHP_SESSION_ACTIVE) session_commit()
;
session_id(session_create_id()); // Session is inactive, no collision check
session_start()
;
by their own decision and risk.
IMHO, other way around should not be the default.
NOTE: Users will need to call session_create_id()
for regenerating
session ID. Therefore, there should be active session already.
Regards,
--
Yasuo Ohgaki
yohgaki@ohgaki.net
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
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
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.
-
If an app needs to access session values, it can and should do this
without indirection through the PHP session ID table. -
Users should generally let PHP choose random IDs.
-
If PHP is to allow a user to chose its own session IDs, avoiding
collision is should that user's responsibility. -
Generating unique unpredictable IDs (without requiring collision
detection) is a common problem with known and trusted solutions.
Tom
Hi Tom,
Rather than argue the details of randomness, I have more basic comments.
- 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?
- Users should generally let PHP choose random IDs.
I agree.
- 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.
- 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
Hi Tom,
Rather than argue the details of randomness, I have more basic comments.
- 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?
-
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. -
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.
- Users should generally let PHP choose random IDs.
I agree.
- 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?
- 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.
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
Hi all,
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
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/
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 UTCThank 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