-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[PasswordHasher] Make bcrypt nul byte hash test tolerant to PHP related failures #54858
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
Conversation
These tests already contain a PHP version detection logic for this purpose. Should we rather fix that instead of adding another layer? |
You mean adding |
if (\PHP_VERSION_ID < 80218 || \PHP_VERSION_ID >= 80300 && \PHP_VERSION_ID < 80305) {
// password_hash() does not accept passwords containing NUL bytes since PHP 8.2.18 and 8.3.5
$this->assertFalse($hasher->verify(password_hash($plainPassword, \PASSWORD_BCRYPT, ['cost' => 4]), $plainPassword));
} This part should probably be updated. |
But it is actually a bit different. In the part you highlight, we still try to hash+verify, whereas prior to 8.2, Checking However, changing from the annotation to an |
This line should always be executed as our password hasher makes sure to not pass the nul byte to |
What puzzles me here: PHP 7.2 is around for a while already, why does this test start to become a problem just now? |
Ok I understand what I missed, I didn't see that the calls in |
same for me, could it be that the Docker image that we use in the CI uses PHP versions that have patches backported? 🤔 |
Here is the commit responsible of the failure: php/php-src@11f2568 |
In that case, shall we drop the version detection entirely and make the test tolerant to the error raised by PHP? |
It seems that |
for a job based on PHP 7.4.33 I would have expected to to have that same instruction appear in https://github.com/php/php-src/blob/PHP-7.4.33/ext/standard/password.c too |
Nope, when a plain password contains nul it's always sha512 hashed and base 64 encoded (the same is also true if the password is longer than or equal to 72 characters no matter if it contains nul). |
Maybe @shivammathur can tell us if that patch has been backported to his PHP 7 builds. Sorry for the shameless ping. 😓 |
Oh yes my bad, nothing to do in the hasher indeed |
Answering my own question: Yes, the patch has been backported as shivammathur/php-src-backports@d22d9eb. Much love for this repository, @shivammathur. ❤️ In that case, I'm back to my proposal in #54858 (comment) |
yes, makes sense to me then |
259547a
to
67aa6ca
Compare
What do you think of this new approach? |
try { | ||
$verified = $hasher->verify($hasher->hash($plainPassword), $plainPassword); | ||
|
||
$this->assertTrue($hasher->verify($hasher->hash($plainPassword), $plainPassword)); | ||
$this->assertTrue($verified); | ||
} catch (\ValueError $error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep the try
block minimal and only include the call that you expect to raise the ValueError
. Given that ValueError
is a very generic exception class, we should also sniff the exception message to make sure we're skipping the test for the right reasons.
Please also add a clarifying comment hinting at the PHP commit that caused this change.
I think, we should also skip the test for PHP >= 8.4 entirely (via annotation). This way, we can find and delete it once we open a branch that doesn't support PHP 8.3 anymore (likely Symfony 8.0).
$this->assertTrue($hasher->verify($hasher->hash($plainPassword), $plainPassword)); | ||
$this->assertTrue($verified); | ||
} catch (\ValueError $error) { | ||
$this->markTestSkipped(sprintf('password_hash() does not accept passwords containing NUL bytes on PHP %s. ', \PHP_VERSION)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$this->markTestSkipped(sprintf('password_hash() does not accept passwords containing NUL bytes on PHP %s. ', \PHP_VERSION)); | |
$this->markTestSkipped('password_hash() does not accept passwords containing NUL bytes.'); |
I would not include the current PHP version here.
67aa6ca
to
b6da05c
Compare
5f131e3
to
acb87ac
Compare
$this->assertFalse($hasher->verify(password_hash($plainPassword, \PASSWORD_BCRYPT, ['cost' => 4]), $plainPassword)); | ||
try { | ||
$hash = password_hash($plainPassword, \PASSWORD_BCRYPT, ['cost' => 4]); | ||
} catch (\ValueError $error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ValueError
error class does not exist on PHP 7. Please double check what the backport raises instead. Maybe catching Throwable
would be okay here, given that we filter out the exception message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated so we check for a Throwable with a specific message. I also checked the case password_hash()
returns null, as implemented in the backport.
b748ada
to
c25c368
Compare
src/Symfony/Component/PasswordHasher/Tests/Hasher/NativePasswordHasherTest.php
Show resolved
Hide resolved
c25c368
to
b1464b9
Compare
src/Symfony/Component/PasswordHasher/Tests/Hasher/NativePasswordHasherTest.php
Outdated
Show resolved
Hide resolved
b1464b9
to
89b2a2c
Compare
Thank you @alexandre-daubois. |
Bcrypt throws on PHP < 8.2 when passing a nul byte. The related test should be skipped for these versions as
$hasher->verify()
return value cannot be asserted.Related failure: https://github.com/symfony/symfony/actions/runs/8980661047/job/24664698662#step:7:1168