From 77f082488154f5ae1aac9ad4da2c18e72149099b Mon Sep 17 00:00:00 2001 From: Christian Futterlieb <christian@futterlieb.ch> Date: Sat, 18 Feb 2017 11:51:07 +0100 Subject: [PATCH] [TASK] Compare password hashes in constant time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to avoid time-based hash-based attacks, the native PHP security functions are used instead of simple string comparisons, when comparing passwords with hashes. Change-Id: I0dbe2c12c5017f9d71ea7628ddd35d919510ac12 Releases: master Resolves: #79888 Related: #79795 Reviewed-on: https://review.typo3.org/51737 Reviewed-by: Helmut Hummel <typo3@helhum.io> Tested-by: Helmut Hummel <typo3@helhum.io> Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Mads Lønne Jensen <mlj@systime.dk> Reviewed-by: Markus Klein <markus.klein@typo3.org> Tested-by: Markus Klein <markus.klein@typo3.org> --- .../saltedpasswords/Classes/Salt/Md5Salt.php | 2 +- .../Classes/Salt/Pbkdf2Salt.php | 2 +- .../Classes/Salt/PhpassSalt.php | 2 +- .../Tests/Unit/Salt/BlowfishSaltTest.php | 27 +++++++++++++++++++ .../Tests/Unit/Salt/Md5SaltTest.php | 27 +++++++++++++++++++ .../Tests/Unit/Salt/Pbkdf2SaltTest.php | 27 +++++++++++++++++++ .../Tests/Unit/Salt/PhpassSaltTest.php | 27 +++++++++++++++++++ 7 files changed, 111 insertions(+), 3 deletions(-) diff --git a/typo3/sysext/saltedpasswords/Classes/Salt/Md5Salt.php b/typo3/sysext/saltedpasswords/Classes/Salt/Md5Salt.php index fc7ba6af88fe..0543b4380942 100644 --- a/typo3/sysext/saltedpasswords/Classes/Salt/Md5Salt.php +++ b/typo3/sysext/saltedpasswords/Classes/Salt/Md5Salt.php @@ -82,7 +82,7 @@ class Md5Salt extends AbstractSalt implements SaltInterface { $isCorrect = false; if ($this->isValidSalt($saltedHashPW)) { - $isCorrect = crypt($plainPW, $saltedHashPW) == $saltedHashPW; + $isCorrect = \password_verify($plainPW, $saltedHashPW); } return $isCorrect; } diff --git a/typo3/sysext/saltedpasswords/Classes/Salt/Pbkdf2Salt.php b/typo3/sysext/saltedpasswords/Classes/Salt/Pbkdf2Salt.php index 3f965c021079..55784725ab4d 100644 --- a/typo3/sysext/saltedpasswords/Classes/Salt/Pbkdf2Salt.php +++ b/typo3/sysext/saltedpasswords/Classes/Salt/Pbkdf2Salt.php @@ -108,7 +108,7 @@ class Pbkdf2Salt extends AbstractSalt implements SaltInterface */ public function checkPassword($plainPW, $saltedHashPW) { - return $this->isValidSalt($saltedHashPW) && $this->getHashedPassword($plainPW, $saltedHashPW) === $saltedHashPW; + return $this->isValidSalt($saltedHashPW) && \hash_equals($this->getHashedPassword($plainPW, $saltedHashPW), $saltedHashPW); } /** diff --git a/typo3/sysext/saltedpasswords/Classes/Salt/PhpassSalt.php b/typo3/sysext/saltedpasswords/Classes/Salt/PhpassSalt.php index 3b538bf0aed4..89d93cb16e2a 100644 --- a/typo3/sysext/saltedpasswords/Classes/Salt/PhpassSalt.php +++ b/typo3/sysext/saltedpasswords/Classes/Salt/PhpassSalt.php @@ -125,7 +125,7 @@ class PhpassSalt extends AbstractSalt implements SaltInterface public function checkPassword($plainPW, $saltedHashPW) { $hash = $this->cryptPassword($plainPW, $saltedHashPW); - return $hash && $saltedHashPW === $hash; + return $hash && \hash_equals($hash, $saltedHashPW); } /** diff --git a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/BlowfishSaltTest.php b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/BlowfishSaltTest.php index d9b4275bdfd3..c1c98e5048b0 100644 --- a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/BlowfishSaltTest.php +++ b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/BlowfishSaltTest.php @@ -133,6 +133,33 @@ class BlowfishSaltTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase $this->objectInstance->setHashCount(null); } + /** + * Tests authentication procedure with fixed password and fixed (pre-generated) hash. + * + * Checks if a "plain-text password" is every time mapped to the + * same "salted password hash" when using the same fixed salt. + * + * @test + */ + public function authenticationWithValidAlphaCharClassPasswordAndFixedHash() + { + $password = 'password'; + $saltedHashPassword = '$2a$07$Rvtl6CyMhR8GZGhHypjwOuydeN0nKFAlgo1LmmGrLowtIrtkov5Na'; + $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword)); + } + + /** + * Tests that authentication procedure fails with broken hash to compare to + * + * @test + */ + public function authenticationFailsWithBrokenHash() + { + $password = 'password'; + $saltedHashPassword = '$2a$07$Rvtl6CyMhR8GZGhHypjwOuydeN0nKFAlgo1LmmGrLowtIrtkov5N'; + $this->assertFalse($this->objectInstance->checkPassword($password, $saltedHashPassword)); + } + /** * Tests authentication procedure with alphabet characters. * diff --git a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Md5SaltTest.php b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Md5SaltTest.php index 96959e5058fc..0a09ed428f79 100644 --- a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Md5SaltTest.php +++ b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Md5SaltTest.php @@ -117,6 +117,33 @@ class Md5SaltTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword), $this->getWarningWhenMethodUnavailable()); } + /** + * Tests authentication procedure with fixed password and fixed (pre-generated) hash. + * + * Checks if a "plain-text password" is every time mapped to the + * same "salted password hash" when using the same fixed salt. + * + * @test + */ + public function authenticationWithValidAlphaCharClassPasswordAndFixedHash() + { + $password = 'password'; + $saltedHashPassword = '$1$GNu9HdMt$RwkPb28pce4nXZfnplVZY/'; + $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable()); + } + + /** + * Tests that authentication procedure fails with broken hash to compare to + * + * @test + */ + public function authenticationFailsWithBrokenHash() + { + $password = 'password'; + $saltedHashPassword = '$1$GNu9HdMt$RwkPb28pce4nXZfnplVZY'; + $this->assertFalse($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable()); + } + /** * Tests authentication procedure with alphabet characters. * diff --git a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Pbkdf2SaltTest.php b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Pbkdf2SaltTest.php index 59292a352f92..4b734f30546a 100644 --- a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Pbkdf2SaltTest.php +++ b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/Pbkdf2SaltTest.php @@ -120,6 +120,33 @@ class Pbkdf2SaltTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase $this->objectInstance->setHashCount(null); } + /** + * Tests authentication procedure with fixed password and fixed (pre-generated) hash. + * + * Checks if a "plain-text password" is every time mapped to the + * same "salted password hash" when using the same fixed salt. + * + * @test + */ + public function authenticationWithValidAlphaCharClassPasswordAndFixedHash() + { + $password = 'password'; + $saltedHashPassword = '$pbkdf2-sha256$1000$woPhT0yoWm3AXJXSjuxJ3w$iZ6EvTulMqXlzr0NO8z5EyrklFcJk5Uw2Fqje68FfaQ'; + $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword)); + } + + /** + * Tests that authentication procedure fails with broken hash to compare to + * + * @test + */ + public function authenticationFailsWithBrokenHash() + { + $password = 'password'; + $saltedHashPassword = '$pbkdf2-sha256$1000$woPhT0yoWm3AXJXSjuxJ3w$iZ6EvTulMqXlzr0NO8z5EyrklFcJk5Uw2Fqje68Ffa'; + $this->assertFalse($this->objectInstance->checkPassword($password, $saltedHashPassword)); + } + /** * Tests authentication procedure with alphabet characters. * diff --git a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/PhpassSaltTest.php b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/PhpassSaltTest.php index 0df190f38a13..4772385b9d90 100644 --- a/typo3/sysext/saltedpasswords/Tests/Unit/Salt/PhpassSaltTest.php +++ b/typo3/sysext/saltedpasswords/Tests/Unit/Salt/PhpassSaltTest.php @@ -117,6 +117,33 @@ class PhpassSaltTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase $this->objectInstance->setHashCount(null); } + /** + * Tests authentication procedure with fixed password and fixed (pre-generated) hash. + * + * Checks if a "plain-text password" is every time mapped to the + * same "salted password hash" when using the same fixed salt. + * + * @test + */ + public function authenticationWithValidAlphaCharClassPasswordAndFixedHash() + { + $password = 'password'; + $saltedHashPassword = '$P$C7u7E10SBEie/Jbdz0jDtUcWhzgOPF.'; + $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword)); + } + + /** + * Tests that authentication procedure fails with broken hash to compare to + * + * @test + */ + public function authenticationFailsWithBrokenHash() + { + $password = 'password'; + $saltedHashPassword = '$P$C7u7E10SBEie/Jbdz0jDtUcWhzgOPF'; + $this->assertFalse($this->objectInstance->checkPassword($password, $saltedHashPassword)); + } + /** * Tests authentication procedure with alphabet characters. * -- GitLab