13. The Wrong Way
<?php
class SecurityFail
{
// Encrypt Passwords for Highest Level of Security.
static public function encrypt($pword)
{
return md5($pword);
}
}
http://csiphp.com/blog/2012/02/16/encrypt-passwords-for-highest-level-of-security/
Wednesday, January 29, 14
20. password_hash
‣
Creates a new password hash
http://www.php.net/manual/en/function.password-hash.php
Wednesday, January 29, 14
21. password_hash
‣
Strong, one-way hashing algorithm
‣
Creates a new password hash
http://www.php.net/manual/en/function.password-hash.php
Wednesday, January 29, 14
22. password_hash
‣
Strong, one-way hashing algorithm
‣
Creates a new password hash
‣
PASSWORD_DEFAULT or PASSWORD_BCRYPT
http://www.php.net/manual/en/function.password-hash.php
Wednesday, January 29, 14
23. password_hash
‣
Strong, one-way hashing algorithm
‣
Creates a new password hash
‣
‣
PASSWORD_DEFAULT or PASSWORD_BCRYPT
Optional cost and salt
http://www.php.net/manual/en/function.password-hash.php
Wednesday, January 29, 14
26. password_hash
‣
Your DB’s password field should be varchar(255)
‣
Always use PASSWORD_DEFAULT
http://www.php.net/manual/en/function.password-hash.php
Wednesday, January 29, 14
27. password_hash
‣
Your DB’s password field should be varchar(255)
‣
Do not use your own salt
‣
Always use PASSWORD_DEFAULT
http://www.php.net/manual/en/function.password-hash.php
Wednesday, January 29, 14
28. password_hash
‣
Your DB’s password field should be varchar(255)
‣
Do not use your own salt
‣
Check for an appropriate cost using the example script
‣ in the manual
Always use PASSWORD_DEFAULT
http://www.php.net/manual/en/function.password-hash.php
Wednesday, January 29, 14
43. Password Validator
‣
Will rehash when needed
‣
Will upgrade legacy passwords
‣
Validates passwords against password_hash
Wednesday, January 29, 14
44. Password Validator
‣
Will rehash when needed
‣
Will upgrade legacy passwords
‣
Requires PHP 5.3.7+
‣
Validates passwords against password_hash
Wednesday, January 29, 14
45. Password Validator
‣
Will rehash when needed
‣
Will upgrade legacy passwords
‣
Requires PHP 5.3.7+
‣
(No version for <=5.3.6 is in the works)
‣
Validates passwords against password_hash
Wednesday, January 29, 14
46. Password Validator
use JeremyKendallPasswordPasswordValidator;
use JeremyKendallPasswordResult as ValidationResult;
$passwordHash = password_hash('password', PASSWORD_DEFAULT);
$validator = new PasswordValidator();
$result = $validator->isValid('password', $passwordHash);
$valid = $result->isValid();
$code = $result->getCode();
// $valid = true
// $code = ValidationResult::SUCCESS
Wednesday, January 29, 14
47. Password Validator
use JeremyKendallPasswordPasswordValidator;
use JeremyKendallPasswordResult as ValidationResult;
$options = array('cost' => 9);
$passwordHash = password_hash('password', PASSWORD_DEFAULT, $options);
$validator = new PasswordValidator();
$validator->setOptions($options);
$result = $validator->isValid('password', $passwordHash);
$valid = $result->isValid();
$code = $result->getCode();
// $valid = true
// $code = ValidationResult::SUCCESS
Wednesday, January 29, 14
48. Password Validator
use JeremyKendallPasswordPasswordValidator;
use JeremyKendallPasswordResult as ValidationResult;
$options = array('cost' => 9);
$passwordHash = password_hash('password', PASSWORD_DEFAULT, $options);
$validator = new PasswordValidator();
// Remember, default cost is 10, so a cost 9 hash gets rehashed
$result = $validator->isValid('password', $passwordHash);
$valid = $result->isValid();
$code = $result->getCode();
$hash = $result->getPassword();
// $valid = true
// $code = ValidationResult::SUCCESS_PASSWORD_REHASHED
// $hash = the new, rehashed password. Save it!
Wednesday, January 29, 14
49. Fine, But We’re Not Using
password_hash Yet ...
Wednesday, January 29, 14
57. Upgrade Decorator
‣
... but you’re ready to do things the right way
‣
Used when you’re not already using password_hash ...
Wednesday, January 29, 14
58. Upgrade Decorator
‣
... but you’re ready to do things the right way
‣
Accepts an instance of PasswordValidatorInterface ...
‣
Used when you’re not already using password_hash ...
Wednesday, January 29, 14
59. Upgrade Decorator
‣
... but you’re ready to do things the right way
‣
Accepts an instance of PasswordValidatorInterface ...
‣
... and a validation callback
‣
Used when you’re not already using password_hash ...
Wednesday, January 29, 14
60. Upgrade Decorator
// Somewhere in your authentication script
if (hash('sha512', $password) === $passwordHash) {
$valid = true;
}
$valid = false;
Wednesday, January 29, 14
61. Upgrade Decorator
// Same authentication check expressed as a callback
$validationCallback = function ($password, $passwordHash) {
if (hash('sha512', $password) === $passwordHash) {
return true;
}
return false;
};
Wednesday, January 29, 14
62. Upgrade Decorator
$validator = new UpgradeDecorator(
new PasswordValidator(),
$validationCallback
);
$passwordHash = hash('sha512', 'password');
$result = $validator->isValid('password', $passwordHash);
$valid = $result->isValid();
$code = $result->getCode();
$hash = $result->getPassword();
// $valid = true
// $code = ValidationResult::SUCCESS_PASSWORD_REHASHED
// $hash = the new, rehashed password. Save it!
Wednesday, January 29, 14
63. Fine, But Now I Have to Test
for SUCCESS_PASSWORD_REHASHED
Every Time
Wednesday, January 29, 14
67. Storage Decorator
‣
Accepts two constructor args:
‣
Instance of PasswordValidatorInterface
‣
Automatically stores all rehashed passwords
Wednesday, January 29, 14
68. Storage Decorator
‣
Accepts two constructor args:
‣
Instance of PasswordValidatorInterface
‣
Instance of StorageInterface
‣
Automatically stores all rehashed passwords
Wednesday, January 29, 14
69. StorageInterface
interface StorageInterface
{
/**
* Updates user's password in persistent storage
*
* @param string $identity Unique user identifier
* @param string $password New password hash
*/
public function updatePassword($identity, $password);
}
Wednesday, January 29, 14
70. UserDao
use JeremyKendallPasswordStorageStorageInterface;
class UserDao implements StorageInterface
{
protected $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function updatePassword($identity, $newPasswordHash)
{
$sql = 'UPDATE users SET passwordHash = :passwordHash WHERE identity = :identity';
$stmt = $this->db->prepare($sql);
$stmt->execute(array('passwordHash' => $newPasswordHash, 'identity' => $identity));
return $this->find($identity);
}
}
Wednesday, January 29, 14
71. Storage Decorator
use JeremyKendallPasswordDecoratorStorageDecorator;
$validator = new StorageDecorator($upgradeDecorator, $userDao);
// Uses the optional third argument for PasswordValidatorInterface::isValid()
$result = $validator->isValid('password', $passwordHash, 'arthur@arthurdent.com');
// Result is the same as any other validation attempt except ...
// ... ValidationResult::SUCCESS_PASSWORD_REHASHED hashes are automatically persisted!
Wednesday, January 29, 14
74. Recap
‣
Use Password Validator to make it dead simple
‣
Use the new PHP password hashing functions
Wednesday, January 29, 14
75. Recap
‣
Use Password Validator to make it dead simple
‣
If you’re not at PHP 5.5, use password_compat
‣
Use the new PHP password hashing functions
Wednesday, January 29, 14
76. Recap
‣
Use Password Validator to make it dead simple
‣
If you’re not at PHP 5.5, use password_compat
‣
If you’re not at PHP 5.3.7+, UPGRADE
‣
Use the new PHP password hashing functions
Wednesday, January 29, 14
77. Recap
‣
Use Password Validator to make it dead simple
‣
If you’re not at PHP 5.5, use password_compat
‣
If you’re not at PHP 5.3.7+, UPGRADE
‣
If you can’t upgrade, use OpenWall’s phpass
‣
Use the new PHP password hashing functions
Wednesday, January 29, 14
78. Recap
‣
Use Password Validator to make it dead simple
‣
If you’re not at PHP 5.5, use password_compat
‣
If you’re not at PHP 5.3.7+, UPGRADE
‣
If you can’t upgrade, use OpenWall’s phpass
‣
DO NOT ROLL YOUR OWN
‣
Use the new PHP password hashing functions
Wednesday, January 29, 14