password hashing: the right way

Post on 01-Sep-2014

1.277 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

Password Hashing: The Right Way

Jeremy Kendall - Memphis PHPJanuary 28, 2014

Wednesday, January 29, 14

Wednesday, January 29, 14

I love to code

Wednesday, January 29, 14

I love to code

I’m terribly forgetful

Wednesday, January 29, 14

I love to code

I’m terribly forgetful

I take pictures

Wednesday, January 29, 14

I love to code

I’m terribly forgetful

I take pictures

I work at OpenSky

Wednesday, January 29, 14

I’m a Little Off My Game

Wednesday, January 29, 14

What Qualifies Me To Talk About Security?

Wednesday, January 29, 14

Not Much

Wednesday, January 29, 14

Not MuchBut that will work in our favor ...

Wednesday, January 29, 14

Cryptography is Hard

Wednesday, January 29, 14

Cryptography is HardPro Tip: Leave it to the experts

Wednesday, January 29, 14

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

The Right Way

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

Wednesday, January 29, 14

The Awesomer Way

Wednesday, January 29, 14

Password Hashing Functions

Wednesday, January 29, 14

Password Hashing FunctionsPro Tip: Use password_compat for PHP 5.3.7+

Wednesday, January 29, 14

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

password_hash

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

Wednesday, January 29, 14

password_hash

‣ Creates a new password hash

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

Wednesday, January 29, 14

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

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

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

password_hash

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

Wednesday, January 29, 14

password_hash

‣ Always use PASSWORD_DEFAULT

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

Wednesday, January 29, 14

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

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

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

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

password_verify

Wednesday, January 29, 14

password_verify

‣ Verifies that a password matches a hash

Wednesday, January 29, 14

password_verify

‣ Verifies that a password matches a hash

‣ Uh, yeah, that’s about it

Wednesday, January 29, 14

password_verify

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

Wednesday, January 29, 14

password_needs_rehash

Wednesday, January 29, 14

password_needs_rehash

‣ Checks password to see if it needs to be updated

Wednesday, January 29, 14

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

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

That’s Awesome and Secure

Wednesday, January 29, 14

But Could It Be Awesomer, Securer, and Easier?

Wednesday, January 29, 14

Password Validator

Wednesday, January 29, 14

Password Validator

‣ Validates passwords against password_hash

Wednesday, January 29, 14

Password Validator

‣ Validates passwords against password_hash

‣Will rehash when needed

Wednesday, January 29, 14

Password Validator

‣ Validates passwords against password_hash

‣Will rehash when needed

‣Will upgrade legacy passwords

Wednesday, January 29, 14

Password Validator

‣ Validates passwords against password_hash

‣Will rehash when needed

‣Will upgrade legacy passwords

‣ Requires PHP 5.3.7+

Wednesday, January 29, 14

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

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

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

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

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

Wednesday, January 29, 14

Decorator Pattern

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

Wednesday, January 29, 14

Decorator Pattern

‣Wrap an object

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

Wednesday, January 29, 14

Decorator Pattern

‣Wrap an object

‣ Change its behavior

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

Wednesday, January 29, 14

Decorator Pattern

‣Wrap an object

‣ Change its behavior

‣ Dynamically attach additional responsibilities

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

Wednesday, January 29, 14

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

Upgrade Decorator

Wednesday, January 29, 14

Upgrade Decorator

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

Wednesday, January 29, 14

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

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

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

Upgrade Decorator

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

$valid = false;

Wednesday, January 29, 14

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

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

Fine, But Now I Have to Test for SUCCESS_PASSWORD_REHASHED

Every Time

Wednesday, January 29, 14

Storage Decorator

Wednesday, January 29, 14

Storage Decorator

‣ Automatically stores all rehashed passwords

Wednesday, January 29, 14

Storage Decorator

‣ Automatically stores all rehashed passwords

‣ Accepts two constructor args:

Wednesday, January 29, 14

Storage Decorator

‣ Automatically stores all rehashed passwords

‣ Accepts two constructor args:

‣ Instance of PasswordValidatorInterface

Wednesday, January 29, 14

Storage Decorator

‣ Automatically stores all rehashed passwords

‣ Accepts two constructor args:

‣ Instance of PasswordValidatorInterface

‣ Instance of StorageInterface

Wednesday, January 29, 14

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

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

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, '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

Recap

Wednesday, January 29, 14

Recap

‣ Use the new PHP password hashing functions

Wednesday, January 29, 14

Recap

‣ Use the new PHP password hashing functions

‣ Use Password Validator to make it dead simple

Wednesday, January 29, 14

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

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

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

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

Resources

Wednesday, January 29, 14

Resources

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

Wednesday, January 29, 14

Resources

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

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

Wednesday, January 29, 14

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

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

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

Thanks!

jeremy@jeremykendall.net

http://about.me/jeremykendall

@jeremykendall

http://365.jeremykendall.net

Wednesday, January 29, 14

top related