Skip to content

Remove hash usage from session ID creation #1850

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 20 commits into from

Conversation

yohgaki
Copy link
Contributor

@yohgaki yohgaki commented Apr 6, 2016

@weltling
Copy link
Contributor

weltling commented May 2, 2016

Yasuo, seems you include the stuff planned in #1769, but also some more as per RFC. IMHO replacing the current parts with php_random_bytes() were already a good step into the direction, to unify the randomness source for all platforms. I guess this substep wouldn't even require an RFC.

Thanks.

@yohgaki
Copy link
Contributor Author

yohgaki commented May 3, 2016

I agree. php_random_bytes() should be used regardless of RFC vote result. I'll make sure it will be in PHP 7.1.

@laruence laruence added the RFC label Jul 2, 2016

return SUCCESS;
}
php_error_docref(NULL, E_WARNING, "session.configuration 'session.sid_length' must between 32 and 256.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a typo? The check above is val >= 22 && val <= PS_MAX_SID_LENGTH - so the minimum length is 22 not 32?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Newer restriction should be 22!


php_error_docref(NULL, E_WARNING, "The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now");
/* Read additiona PS_EXTRA_RAND_BYTES just in case CSPRNG is not safe enough */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo - should be "additional"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I'll fix this!

Yasuo Ohgaki added 11 commits July 12, 2016 18:08
 session.sid_length = 32
 session.sid_bits_per_charactor = 4

However, php.ini-development/production had
 session.hash_func = 0 (MD5 128)
 session.hash_bits_per_character = 5   <--- This differs from compiled default. I didn't notice this.
This config results in shorter session ID length. (26 chars)

Anyway, most PHP installation would have session ID length = 32.

So normal(?) users who are using php.ini-production as php.ini would get

 - session.sid_length=32
 - session.sid_bits_per_character=5

and bits in session ID is 160 bits. (Older config was 128 bits)
. session.sid_bits_per_character (Bits used per byte. 4 to 6. Default: 4)
. If you were using session.hash_func=1(SHA1) and session.hash_bits_per_charactor=6
Use following INIs to achive the same or better session ID strength.
. session.sid_length=32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you note how one needs to calculate the new settings based on the old ones?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it!

@yohgaki
Copy link
Contributor Author

yohgaki commented Aug 12, 2016

merged.

@yohgaki yohgaki closed this Aug 12, 2016
@@ -1457,7 +1443,7 @@ session.hash_function = 0
; Development Value: 5
; Production Value: 5
; http://php.net/session.hash-bits-per-character
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link needs to get updated, but the shortcut http://php.net/session.sid-bits-per-character doesn't seem to exist yet.

; Set session ID character length. This value could be between 22 to 256.
; Shorter length than default is supported only for compatibility reason.
; Users should use 32 or more chars.
; http://php.net/session.sid_length
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This URL doesn't exist and shouldn't it use a dash like all the other links?

break;
#endif /* HAVE_HASH_EXT */
/* Read additional PS_EXTRA_RAND_BYTES just in case CSPRNG is not safe enough */
if (php_random_bytes_throw(rbuf, PS(sid_length) + PS_EXTRA_RAND_BYTES) == FAILURE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems strange to me that it needs to read so many random bytes. In theory it should only require to read sid_length * sid_bits_per_character / 8 bytes. All the extra bytes read seem wasted. Could you explain why this is done this way?

@yohgaki
Copy link
Contributor Author

yohgaki commented Dec 3, 2016

@Tobion
Strictly speaking extra bytes are not needed. Extra bytes read from PRNG is intentional. It's to avoid exposing PRNG state as precaution.

php.ini-* and ini.list.xml is updated now.
Thank you for reporting.

@Tobion
Copy link
Contributor

Tobion commented Dec 3, 2016

@yohgaki I've read the RFC and the discussion on the mailing list and I don't see how reading extra bytes should "mitigate risks of broken PRNG". If the random bytes are predictable, then reading 60 extra bytes does not make them less predictable. So what's the point?

@yohgaki
Copy link
Contributor Author

yohgaki commented Dec 3, 2016

@Tobion
Precaution for broken/predictable/weak PRNG is the whole point.
During RFC discussion, there are "worries" about PRNG state exposure. IMO, ignoring some bits (new bin_to_readable() uses at most 6 bits for PRNG generated byte) for each byte is good enough for hiding PRNG state, but extra 60 bytes are read in addition. There wouldn't be visible performance impact, so don't worry about it. It's faster than older code anyway.

BTW, magic number "60" is chosen because I would like to read more than 64 bytes addition data from PRNG. i.e. When sid_bits_per_character is 6 and sid_length is 22, (60 bytes + 5.5 bytes(22 bits * 2)) > 64 bytes.

@Tobion
Copy link
Contributor

Tobion commented Dec 3, 2016

When sid_bits_per_character is 6 and sid_length is 22, (60 bytes + 5.5 bytes(22 bits * 2)) > 64 bytes.

As far as I see, you are reading 60 + 22 random bytes then. So I cannot follow your logic.

@yohgaki
Copy link
Contributor Author

yohgaki commented Dec 4, 2016

@Tobion

As far as I see, you are reading 60 + 22 random bytes then. So I cannot follow your logic.

It's 65.5 bytes (480 bits + 44 bits), not 88 bytes for that case.

Anyway, I don't insist to have "extra 60 bytes". It just the code proposed with the RFC and extra bytes are added according to RFC discussion with Stas. (Stas worried about PRNG state exposure)

I don't mind removing extra PRNG reads at all indeed. It may hurt performance on some architectures that have slow PRNG generation rate. New code does not use full bits from PRNG and it would be good enough mitigation. IMO.

Length of old session ID string is determined as follows
. Used hash function's bits.
. session.hash_function=0 - MD5 128 bits (This was default)
. session.hash_function=1 - SHA1 192 bits
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sha1 is 160 bits. fixed in #2228

@@ -300,151 +295,24 @@ static char *bin_to_readable(char *in, size_t inlen, char *out, char nbits) /* {
}

*out = '\0';
return out;
return len;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does the method return the length when it is constant? Seems useless.

@Tobion
Copy link
Contributor

Tobion commented Dec 4, 2016

It's 65.5 bytes (480 bits + 44 bits), not 88 bytes for that case.

@yohgaki this php_random_bytes_throw(rbuf, PS(sid_length) + PS_EXTRA_RAND_BYTES) reads 88 random bytes. I don't see how you can end up with 65.5 bytes there...

@yohgaki
Copy link
Contributor Author

yohgaki commented Dec 4, 2016

@Tobion
I'm lost.
We are talking about "extra bytes(bits) read", aren't we?

Anyway, the code reads more than enough extra bytes from PRNG to avoid exposing PRNG state. If you would like to remove it, write RFC for it. I wouldn't oppose it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants