[Security] limited the password length passed to encoders
This commit is contained in:
parent
0375dc8f9f
commit
67d4a8f8af
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Security\Core\Encoder;
|
|||
|
||||
use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
|
||||
use Symfony\Component\Security\Core\Util\SecureRandomInterface;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
|
||||
/**
|
||||
* @author Elnur Abdurrakhimov <elnur@elnur.pro>
|
||||
|
@ -60,6 +61,10 @@ class BCryptPasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function encodePassword($raw, $salt)
|
||||
{
|
||||
if ($this->isPasswordTooLong($raw)) {
|
||||
throw new BadCredentialsException('Invalid password.');
|
||||
}
|
||||
|
||||
if (function_exists('password_hash')) {
|
||||
return password_hash($raw, PASSWORD_BCRYPT, array('cost' => $this->cost));
|
||||
}
|
||||
|
@ -78,6 +83,10 @@ class BCryptPasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function isPasswordValid($encoded, $raw, $salt)
|
||||
{
|
||||
if ($this->isPasswordTooLong($raw)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (function_exists('password_verify')) {
|
||||
return password_verify($raw, $encoded);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ use Symfony\Component\Security\Core\Util\StringUtils;
|
|||
*/
|
||||
abstract class BasePasswordEncoder implements PasswordEncoderInterface
|
||||
{
|
||||
const MAX_PASSWORD_LENGTH = 4096;
|
||||
|
||||
/**
|
||||
* Demerges a merge password and salt string.
|
||||
*
|
||||
|
@ -83,4 +85,14 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
|
|||
{
|
||||
return StringUtils::equals($password1, $password2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the password is too long.
|
||||
*
|
||||
* @return Boolean true if the password is too long, false otherwise
|
||||
*/
|
||||
protected function isPasswordTooLong($password)
|
||||
{
|
||||
return strlen($password) > self::MAX_PASSWORD_LENGTH;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Security\Core\Encoder;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
|
||||
/**
|
||||
* MessageDigestPasswordEncoder uses a message digest algorithm.
|
||||
*
|
||||
|
@ -41,6 +43,10 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function encodePassword($raw, $salt)
|
||||
{
|
||||
if ($this->isPasswordTooLong($raw)) {
|
||||
throw new BadCredentialsException('Invalid password.');
|
||||
}
|
||||
|
||||
if (!in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
@ -61,6 +67,6 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function isPasswordValid($encoded, $raw, $salt)
|
||||
{
|
||||
return $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Security\Core\Encoder;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
|
||||
/**
|
||||
* Pbkdf2PasswordEncoder uses the PBKDF2 (Password-Based Key Derivation Function 2).
|
||||
*
|
||||
|
@ -54,6 +56,10 @@ class Pbkdf2PasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function encodePassword($raw, $salt)
|
||||
{
|
||||
if ($this->isPasswordTooLong($raw)) {
|
||||
throw new BadCredentialsException('Invalid password.');
|
||||
}
|
||||
|
||||
if (!in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
@ -72,7 +78,7 @@ class Pbkdf2PasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function isPasswordValid($encoded, $raw, $salt)
|
||||
{
|
||||
return $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||
}
|
||||
|
||||
private function hashPbkdf2($algorithm, $password, $salt, $iterations, $length = 0)
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Security\Core\Encoder;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
|
||||
/**
|
||||
* PlaintextPasswordEncoder does not do any encoding.
|
||||
*
|
||||
|
@ -35,6 +37,10 @@ class PlaintextPasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function encodePassword($raw, $salt)
|
||||
{
|
||||
if ($this->isPasswordTooLong($raw)) {
|
||||
throw new BadCredentialsException('Invalid password.');
|
||||
}
|
||||
|
||||
return $this->mergePasswordAndSalt($raw, $salt);
|
||||
}
|
||||
|
||||
|
@ -43,6 +49,10 @@ class PlaintextPasswordEncoder extends BasePasswordEncoder
|
|||
*/
|
||||
public function isPasswordValid($encoded, $raw, $salt)
|
||||
{
|
||||
if ($this->isPasswordTooLong($raw)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pass2 = $this->mergePasswordAndSalt($raw, $salt);
|
||||
|
||||
if (!$this->ignorePasswordCase) {
|
||||
|
|
|
@ -109,4 +109,21 @@ class BCryptPasswordEncoderTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
|
||||
*/
|
||||
public function testEncodePasswordLength()
|
||||
{
|
||||
$encoder = new BCryptPasswordEncoder($this->secureRandom, self::VALID_COST);
|
||||
|
||||
$encoder->encodePassword(str_repeat('a', 5000), 'salt');
|
||||
}
|
||||
|
||||
public function testCheckPasswordLength()
|
||||
{
|
||||
$encoder = new BCryptPasswordEncoder($this->secureRandom, self::VALID_COST);
|
||||
|
||||
$this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,12 @@ class BasePasswordEncoderTest extends \PHPUnit_Framework_TestCase
|
|||
$this->invokeMergePasswordAndSalt('password', '{foo}');
|
||||
}
|
||||
|
||||
public function testIsPasswordTooLong()
|
||||
{
|
||||
$this->assertTrue($this->invokeIsPasswordTooLong(str_repeat('a', 10000)));
|
||||
$this->assertFalse($this->invokeIsPasswordTooLong(str_repeat('a', 10)));
|
||||
}
|
||||
|
||||
protected function invokeDemergePasswordAndSalt($password)
|
||||
{
|
||||
$encoder = new PasswordEncoder();
|
||||
|
@ -82,4 +88,14 @@ class BasePasswordEncoderTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
return $m->invoke($encoder, $p1, $p2);
|
||||
}
|
||||
|
||||
protected function invokeIsPasswordTooLong($p)
|
||||
{
|
||||
$encoder = new PasswordEncoder();
|
||||
$r = new \ReflectionObject($encoder);
|
||||
$m = $r->getMethod('isPasswordTooLong');
|
||||
$m->setAccessible(true);
|
||||
|
||||
return $m->invoke($encoder, $p);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,4 +42,21 @@ class MessageDigestPasswordEncoderTest extends \PHPUnit_Framework_TestCase
|
|||
$encoder = new MessageDigestPasswordEncoder('foobar');
|
||||
$encoder->encodePassword('password', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
|
||||
*/
|
||||
public function testEncodePasswordLength()
|
||||
{
|
||||
$encoder = new MessageDigestPasswordEncoder();
|
||||
|
||||
$encoder->encodePassword(str_repeat('a', 5000), 'salt');
|
||||
}
|
||||
|
||||
public function testCheckPasswordLength()
|
||||
{
|
||||
$encoder = new MessageDigestPasswordEncoder();
|
||||
|
||||
$this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,4 +42,21 @@ class Pbkdf2PasswordEncoderTest extends \PHPUnit_Framework_TestCase
|
|||
$encoder = new Pbkdf2PasswordEncoder('foobar');
|
||||
$encoder->encodePassword('password', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
|
||||
*/
|
||||
public function testEncodePasswordLength()
|
||||
{
|
||||
$encoder = new Pbkdf2PasswordEncoder('foobar');
|
||||
|
||||
$encoder->encodePassword(str_repeat('a', 5000), 'salt');
|
||||
}
|
||||
|
||||
public function testCheckPasswordLength()
|
||||
{
|
||||
$encoder = new Pbkdf2PasswordEncoder('foobar');
|
||||
|
||||
$this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,4 +36,21 @@ class PlaintextPasswordEncoderTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$this->assertSame('foo', $encoder->encodePassword('foo', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
|
||||
*/
|
||||
public function testEncodePasswordLength()
|
||||
{
|
||||
$encoder = new PlaintextPasswordEncoder();
|
||||
|
||||
$encoder->encodePassword(str_repeat('a', 5000), 'salt');
|
||||
}
|
||||
|
||||
public function testCheckPasswordLength()
|
||||
{
|
||||
$encoder = new PlaintextPasswordEncoder();
|
||||
|
||||
$this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt'));
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue