Skip to content

[Security] Use hash_equals for constant-time string comparison (again) #11822

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

Merged
merged 2 commits into from
Sep 10, 2014

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Sep 1, 2014

Q A
Bug fix? no
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets n/a
License MIT
Doc PR n/a

Use the hash_equals function (introduced in PHP 5.6) for timing attack safe string comparison when available.

Add in the DocBlock that length will leak (#11797 (comment)).

@aforsblo
Copy link
Contributor

aforsblo commented Sep 2, 2014

👍

2 similar comments
@stof
Copy link
Member

stof commented Sep 2, 2014

👍

@sstok
Copy link
Contributor

sstok commented Sep 2, 2014

👍

@@ -35,6 +36,10 @@ private function __construct() {}
*/
public static function equals($knownString, $userInput)
{
if (function_exists('hash_equals')) {
return hash_equals((string) $knownString, (string) $userInput);
Copy link
Contributor

Choose a reason for hiding this comment

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

no need to cast to string since according to phpdoc only strings are accepted by equals

Copy link
Member Author

Choose a reason for hiding this comment

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

If you don't cast, the C implementation will throw a warning: https://github.com/php/php-src/blob/master/ext/hash/hash.c#L736
The PHP implementation doesn't throw anything. The cast is mandatory to avoid BC break.

Copy link
Member Author

Choose a reason for hiding this comment

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

Btw, I've added tests for that: #11808

Copy link
Contributor

Choose a reason for hiding this comment

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

Well the tests you did are wrong. You pass null and int to a function that excepts a string. Of course the behavior is undefined then.

Copy link
Member Author

Choose a reason for hiding this comment

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

The current PHP implementation implicitly casts inputs to string: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Util/StringUtils.php#L39

If you don't add the cast, the behavior of the function will change (throw warning, was not throwing anything before). This matter especially if arguments are objects implementing the __toString() method.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then why did you add tests for something that is not supported?

Copy link
Member Author

Choose a reason for hiding this comment

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

To be sure that this patch (and future work on this method) behave in a similar fashion than the previous implementation. Especially because it has been asked to merge it in 2.3.

Copy link
Member Author

Choose a reason for hiding this comment

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

(And I don't know a way to indicate in a PHPDoc "string or an object implementing __toString()" and mixed is not appropriate because passing an array will throw a notice and an object without __toString() method will throw an error [http://dunglas.fr/2014/02/casting-php-types-to-string/]).

Copy link
Contributor

Choose a reason for hiding this comment

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

Well ok the string cast might be good to be more fault-tolerant. I think it's just important to do so for good reasons. Otherwise we could add string casts in every method in symfony where strings are expected.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, this is only to keep consistency with the old behavior. Anyway, a new PHP project targeting PHP 5.6+ should directly use hash_equals to avoid overhead.

@Tobion
Copy link
Contributor

Tobion commented Sep 2, 2014

👍

@dunglas
Copy link
Member Author

dunglas commented Sep 4, 2014

Cast to string earlier.
The method now behave like before #11574 merging and tests of #11808 works again (#11808 (comment)).

array('', ''),
array(123, 123),
array(null, ''),
array(null, null),
Copy link
Contributor

Choose a reason for hiding this comment

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

what about null and false

Copy link
Member Author

Choose a reason for hiding this comment

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

I've just copied data of the php.net implementation. I'll add it.

@fabpot fabpot added the Security label Sep 5, 2014
@fabpot
Copy link
Member

fabpot commented Sep 10, 2014

Thank you @dunglas.

@fabpot fabpot merged commit 3071557 into symfony:2.3 Sep 10, 2014
fabpot added a commit that referenced this pull request Sep 10, 2014
…arison (again) (dunglas)

This PR was merged into the 2.3 branch.

Discussion
----------

[Security] Use hash_equals for constant-time string comparison (again)

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | n/a

Use the `hash_equals` function (introduced in PHP 5.6) for timing attack safe string comparison when available.

Add in the DocBlock that length will leak (#11797 (comment)).

Commits
-------

3071557 [Security] Add more tests for StringUtils::equals
03bd74b [Security] Use hash_equals for constant-time string comparison
@dunglas dunglas deleted the hash_equals_2.3 branch December 5, 2015 09:01
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.

6 participants