password hashing: the right way

85
Password Hashing: The Right Way Jeremy Kendall - Memphis PHP January 28, 2014 Wednesday, January 29, 14

Upload: jeremy-kendall

Post on 01-Sep-2014

1.277 views

Category:

Technology


3 download

DESCRIPTION

Introduces the new PHP password hashing functions and Password Validator library.

TRANSCRIPT

Page 1: Password Hashing: The Right Way

Password Hashing: The Right Way

Jeremy Kendall - Memphis PHPJanuary 28, 2014

Wednesday, January 29, 14

Page 2: Password Hashing: The Right Way

Wednesday, January 29, 14

Page 3: Password Hashing: The Right Way

I love to code

Wednesday, January 29, 14

Page 4: Password Hashing: The Right Way

I love to code

I’m terribly forgetful

Wednesday, January 29, 14

Page 5: Password Hashing: The Right Way

I love to code

I’m terribly forgetful

I take pictures

Wednesday, January 29, 14

Page 6: Password Hashing: The Right Way

I love to code

I’m terribly forgetful

I take pictures

I work at OpenSky

Wednesday, January 29, 14

Page 7: Password Hashing: The Right Way

I’m a Little Off My Game

Wednesday, January 29, 14

Page 8: Password Hashing: The Right Way

What Qualifies Me To Talk About Security?

Wednesday, January 29, 14

Page 9: Password Hashing: The Right Way

Not Much

Wednesday, January 29, 14

Page 10: Password Hashing: The Right Way

Not MuchBut that will work in our favor ...

Wednesday, January 29, 14

Page 11: Password Hashing: The Right Way

Cryptography is Hard

Wednesday, January 29, 14

Page 12: Password Hashing: The Right Way

Cryptography is HardPro Tip: Leave it to the experts

Wednesday, January 29, 14

Page 13: Password Hashing: The Right Way

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

Page 14: Password Hashing: The Right Way

The Right Way

http://php.net/manual/en/ref.password.php

Wednesday, January 29, 14

Page 15: Password Hashing: The Right Way

The Awesomer Way

Wednesday, January 29, 14

Page 16: Password Hashing: The Right Way

Password Hashing Functions

Wednesday, January 29, 14

Page 17: Password Hashing: The Right Way

Password Hashing FunctionsPro Tip: Use password_compat for PHP 5.3.7+

Wednesday, January 29, 14

Page 18: Password Hashing: The Right Way

Password Hashing FunctionsPro Tip: Use password_compat for PHP 5.3.7+

Pro Tip: Use phpass for PHP <= 5.3.6

Wednesday, January 29, 14

Page 19: Password Hashing: The Right Way

password_hash

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 20: Password Hashing: The Right Way

password_hash

‣ Creates a new password hash

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 21: Password Hashing: The Right Way

password_hash

‣ Creates a new password hash

‣ Strong, one-way hashing algorithm

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 22: Password Hashing: The Right Way

password_hash

‣ Creates a new password hash

‣ Strong, one-way hashing algorithm

‣ PASSWORD_DEFAULT or PASSWORD_BCRYPT

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 23: Password Hashing: The Right Way

password_hash

‣ Creates a new password hash

‣ Strong, one-way hashing algorithm

‣ PASSWORD_DEFAULT or PASSWORD_BCRYPT

‣ Optional cost and salt

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 24: Password Hashing: The Right Way

password_hash

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 25: Password Hashing: The Right Way

password_hash

‣ Always use PASSWORD_DEFAULT

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 26: Password Hashing: The Right Way

password_hash

‣ Always use PASSWORD_DEFAULT

‣ Your DB’s password field should be varchar(255)

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 27: Password Hashing: The Right Way

password_hash

‣ Always use PASSWORD_DEFAULT

‣ Your DB’s password field should be varchar(255)

‣ Do not use your own salt

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 28: Password Hashing: The Right Way

password_hash

‣ Always use PASSWORD_DEFAULT

‣ 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

http://www.php.net/manual/en/function.password-hash.php

Wednesday, January 29, 14

Page 29: Password Hashing: The Right Way

password_hash

$hash = password_hash('secret pass', PASSWORD_DEFAULT);

// or

$options = array('cost' => 12);$hash = password_hash('secret pass', PASSWORD_DEFAULT, $options);

Wednesday, January 29, 14

Page 30: Password Hashing: The Right Way

password_verify

Wednesday, January 29, 14

Page 31: Password Hashing: The Right Way

password_verify

‣ Verifies that a password matches a hash

Wednesday, January 29, 14

Page 32: Password Hashing: The Right Way

password_verify

‣ Verifies that a password matches a hash

‣ Uh, yeah, that’s about it

Wednesday, January 29, 14

Page 33: Password Hashing: The Right Way

password_verify

$valid = password_verify($_POST['pass'], $hashFromDb);

Wednesday, January 29, 14

Page 34: Password Hashing: The Right Way

password_needs_rehash

Wednesday, January 29, 14

Page 35: Password Hashing: The Right Way

password_needs_rehash

‣ Checks password to see if it needs to be updated

Wednesday, January 29, 14

Page 36: Password Hashing: The Right Way

password_needs_rehash

‣ Checks password to see if it needs to be updated

‣ Uses both hash and cost to check current hash

Wednesday, January 29, 14

Page 37: Password Hashing: The Right Way

password_needs_rehash

$needsRehash = password_needs_rehash($hashFromDb, PASSWORD_DEFAULT);

// or

$options = array('cost' => 12);$needsRehash = password_needs_rehash($hashFromDb, PASSWORD_DEFAULT, $options);

Wednesday, January 29, 14

Page 38: Password Hashing: The Right Way

That’s Awesome and Secure

Wednesday, January 29, 14

Page 39: Password Hashing: The Right Way

But Could It Be Awesomer, Securer, and Easier?

Wednesday, January 29, 14

Page 40: Password Hashing: The Right Way

Password Validator

Wednesday, January 29, 14

Page 41: Password Hashing: The Right Way

Password Validator

‣ Validates passwords against password_hash

Wednesday, January 29, 14

Page 42: Password Hashing: The Right Way

Password Validator

‣ Validates passwords against password_hash

‣Will rehash when needed

Wednesday, January 29, 14

Page 43: Password Hashing: The Right Way

Password Validator

‣ Validates passwords against password_hash

‣Will rehash when needed

‣Will upgrade legacy passwords

Wednesday, January 29, 14

Page 44: Password Hashing: The Right Way

Password Validator

‣ Validates passwords against password_hash

‣Will rehash when needed

‣Will upgrade legacy passwords

‣ Requires PHP 5.3.7+

Wednesday, January 29, 14

Page 45: Password Hashing: The Right Way

Password Validator

‣ Validates passwords against password_hash

‣Will rehash when needed

‣Will upgrade legacy passwords

‣ Requires PHP 5.3.7+

‣ (No version for <=5.3.6 is in the works)

Wednesday, January 29, 14

Page 46: Password Hashing: The Right Way

Password Validator

use JeremyKendall\Password\PasswordValidator;use JeremyKendall\Password\Result 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

Page 47: Password Hashing: The Right Way

Password Validatoruse JeremyKendall\Password\PasswordValidator;use JeremyKendall\Password\Result 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

Page 48: Password Hashing: The Right Way

Password Validatoruse JeremyKendall\Password\PasswordValidator;use JeremyKendall\Password\Result 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

Page 49: Password Hashing: The Right Way

Fine, But We’re Not Using password_hash Yet ...

Wednesday, January 29, 14

Page 50: Password Hashing: The Right Way

Decorator Pattern

http://en.wikipedia.org/wiki/Decorator_pattern

Wednesday, January 29, 14

Page 51: Password Hashing: The Right Way

Decorator Pattern

‣Wrap an object

http://en.wikipedia.org/wiki/Decorator_pattern

Wednesday, January 29, 14

Page 52: Password Hashing: The Right Way

Decorator Pattern

‣Wrap an object

‣ Change its behavior

http://en.wikipedia.org/wiki/Decorator_pattern

Wednesday, January 29, 14

Page 53: Password Hashing: The Right Way

Decorator Pattern

‣Wrap an object

‣ Change its behavior

‣ Dynamically attach additional responsibilities

http://en.wikipedia.org/wiki/Decorator_pattern

Wednesday, January 29, 14

Page 54: Password Hashing: The Right Way

PasswordValidatorInterface

interface PasswordValidatorInterface{ public function isValid($password, $passwordHash, $identity = null);

public function rehash($password);

public function setOptions(array $options);

public function getOptions();}

Wednesday, January 29, 14

Page 55: Password Hashing: The Right Way

Upgrade Decorator

Wednesday, January 29, 14

Page 56: Password Hashing: The Right Way

Upgrade Decorator

‣ Used when you’re not already using password_hash ...

Wednesday, January 29, 14

Page 57: Password Hashing: The Right Way

Upgrade Decorator

‣ Used when you’re not already using password_hash ...

‣ ... but you’re ready to do things the right way

Wednesday, January 29, 14

Page 58: Password Hashing: The Right Way

Upgrade Decorator

‣ Used when you’re not already using password_hash ...

‣ ... but you’re ready to do things the right way

‣ Accepts an instance of PasswordValidatorInterface ...

Wednesday, January 29, 14

Page 59: Password Hashing: The Right Way

Upgrade Decorator

‣ Used when you’re not already using password_hash ...

‣ ... but you’re ready to do things the right way

‣ Accepts an instance of PasswordValidatorInterface ...

‣ ... and a validation callback

Wednesday, January 29, 14

Page 60: Password Hashing: The Right Way

Upgrade Decorator

// Somewhere in your authentication scriptif (hash('sha512', $password) === $passwordHash) { $valid = true;}

$valid = false;

Wednesday, January 29, 14

Page 61: Password Hashing: The Right Way

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

Page 62: Password Hashing: The Right Way

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

Page 63: Password Hashing: The Right Way

Fine, But Now I Have to Test for SUCCESS_PASSWORD_REHASHED

Every Time

Wednesday, January 29, 14

Page 64: Password Hashing: The Right Way

Storage Decorator

Wednesday, January 29, 14

Page 65: Password Hashing: The Right Way

Storage Decorator

‣ Automatically stores all rehashed passwords

Wednesday, January 29, 14

Page 66: Password Hashing: The Right Way

Storage Decorator

‣ Automatically stores all rehashed passwords

‣ Accepts two constructor args:

Wednesday, January 29, 14

Page 67: Password Hashing: The Right Way

Storage Decorator

‣ Automatically stores all rehashed passwords

‣ Accepts two constructor args:

‣ Instance of PasswordValidatorInterface

Wednesday, January 29, 14

Page 68: Password Hashing: The Right Way

Storage Decorator

‣ Automatically stores all rehashed passwords

‣ Accepts two constructor args:

‣ Instance of PasswordValidatorInterface

‣ Instance of StorageInterface

Wednesday, January 29, 14

Page 69: Password Hashing: The Right Way

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

Page 70: Password Hashing: The Right Way

UserDaouse JeremyKendall\Password\Storage\StorageInterface;

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

Page 71: Password Hashing: The Right Way

Storage Decorator

use JeremyKendall\Password\Decorator\StorageDecorator;

$validator = new StorageDecorator($upgradeDecorator, $userDao);

// Uses the optional third argument for PasswordValidatorInterface::isValid()$result = $validator->isValid('password', $passwordHash, '[email protected]');

// Result is the same as any other validation attempt except ...// ... ValidationResult::SUCCESS_PASSWORD_REHASHED hashes are automatically persisted!

Wednesday, January 29, 14

Page 72: Password Hashing: The Right Way

Recap

Wednesday, January 29, 14

Page 73: Password Hashing: The Right Way

Recap

‣ Use the new PHP password hashing functions

Wednesday, January 29, 14

Page 74: Password Hashing: The Right Way

Recap

‣ Use the new PHP password hashing functions

‣ Use Password Validator to make it dead simple

Wednesday, January 29, 14

Page 75: Password Hashing: The Right Way

Recap

‣ Use the new PHP password hashing functions

‣ Use Password Validator to make it dead simple

‣ If you’re not at PHP 5.5, use password_compat

Wednesday, January 29, 14

Page 76: Password Hashing: The Right Way

Recap

‣ Use the new PHP password hashing functions

‣ 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

Wednesday, January 29, 14

Page 77: Password Hashing: The Right Way

Recap

‣ Use the new PHP password hashing functions

‣ 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

Wednesday, January 29, 14

Page 78: Password Hashing: The Right Way

Recap

‣ Use the new PHP password hashing functions

‣ 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

Wednesday, January 29, 14

Page 79: Password Hashing: The Right Way

Resources

Wednesday, January 29, 14

Page 80: Password Hashing: The Right Way

Resources

‣ PHP Password Hashing Functions: http://php.net/password

Wednesday, January 29, 14

Page 81: Password Hashing: The Right Way

Resources

‣ PHP Password Hashing Functions: http://php.net/password

‣ Original password_hash RFC: https://wiki.php.net/rfc/password_hash

Wednesday, January 29, 14

Page 82: Password Hashing: The Right Way

Resources

‣ PHP Password Hashing Functions: http://php.net/password

‣ Original password_hash RFC: https://wiki.php.net/rfc/password_hash

‣ Password Validator: https://github.com/jeremykendall/password-validator

Wednesday, January 29, 14

Page 83: Password Hashing: The Right Way

Resources

‣ PHP Password Hashing Functions: http://php.net/password

‣ Original password_hash RFC: https://wiki.php.net/rfc/password_hash

‣ Password Validator: https://github.com/jeremykendall/password-validator

‣ password_compat: https://github.com/ircmaxell/password_compat

Wednesday, January 29, 14

Page 84: Password Hashing: The Right Way

Resources

‣ PHP Password Hashing Functions: http://php.net/password

‣ Original password_hash RFC: https://wiki.php.net/rfc/password_hash

‣ Password Validator: https://github.com/jeremykendall/password-validator

‣ password_compat: https://github.com/ircmaxell/password_compat

‣ OpenWall phpass: http://www.openwall.com/phpass/

Wednesday, January 29, 14

Page 85: Password Hashing: The Right Way

Thanks!

[email protected]

http://about.me/jeremykendall

@jeremykendall

http://365.jeremykendall.net

Wednesday, January 29, 14