password_hash这个密码哈希扩展为您创建在计算上复杂的安全的密码哈希值,包括在幕后生成和处理随机的 SALT。在对您想要计算哈希值的密码调用 password_hash() 的最简单用例中,该扩展会为您处理所有事情。您还需要提供第二个参数:您想要扩展使用的哈希算法。您有两种选择,但在目前,指定 PASSWORD_DEFAULT 常量是最佳选择。
<?php $hash = password_hash('correct horse battery staple', PASSWORD_DEFAULT);
指定 cost 参数
也可提供第三个参数,这是一个更改哈希值生成方式的选项数组。您可以在这里指定 SALT,但最好是不指定 SALT,并允许为您生成随机 SALT。更重要的是,在这个数组中,您可以指定一个 cost 值。此值(默认值为 10)可以确定该算法应多复杂,进而确定生成哈希值将花费多长时间。(将此值视为更改算法本身重新运行的次数,以减缓计算。)如果想要一个更安全的密码,而且您的计算机能够处理它,您可以像这样执行调用:
<?php $hash = password_hash('correct horse battery staple', PASSWORD_DEFAULT, ['cost' => 14]);
验证生成的密码
因为前面两个示例中的密码是使用一个随机 SALT 过程生成的,所以我无法直接知道相关的 SALT。因此,如果我尝试再次运行 password_hash() 并比较字符串,以此作为验证密码的方式,结果将会不匹配。每次您调用该函数,都会生成一个新 SALT,返回的哈希值也不同。所以该扩展提供了第二个函数 password_verify(),它为您处理验证过程。您调用 password_verify(),传入用户所提供的密码和存储的哈希值,如果密码是正确的,该函数返回一个布尔值 TRUE,否则返回 FALSE:
<?php if (password_verify($password, $hash)) { // Correct Password }
通过使用新的密码哈希扩展,您可以将您的代码库提升到如今的安全标准水平。但仅在几年前,专家曾说过,SHA-1 是一种最佳实践解决方案。那么,如果它不是最佳实践,当 密码加密需要更强时,会发生什么?幸运的是,新扩展有一个内置的功能考虑了这一可能性。
可以使用 password_needs_rehash() 函数(在幕后)检测存储的密码是否与您指定的当前安全需求相匹配。如果不匹配,原因可能是,您增加了 cost 参数,或者一个新的 PHP 版本在幕后更改为一种不同的哈希算法。正因如此,PASSWORD_DEFAULT 应当是您首选的算法;此选项始终会使您的软件使用当前的最佳实践版本。
此功能的使用更加复杂,但不是过于复杂。核对用户的密码时(比如用户尝试登录时),您需要执行一个额外的任务:调用 password_needs_rehash(),它接受与 password_hash() 类似的参数。password_needs_rehash() 函数针对新请求的安全设置来检查所提供的密码哈希值。如果密码哈希值与这些设置不匹配,那么该函数会向您报告这一事实。
一些程序员在这里难以理解,因为 password_needs_rehash() 函数所做的一切都是为了让您知道密码是否需要重新计算哈希值。然后是否生成密码的新哈希值并保存它,这完全取决于您,因为密码扩展不知道您需要如何存储密码。
<?php class User { // Store password options so that rehash & hash can share them: const HASH = PASSWORD_DEFAULT; const COST = 14; // Internal data storage about the user: public $data; // Mock constructor: public function __construct() { // Read data from the database, storing it into $data such as: // $data->passwordHash and $data->username $this->data = new stdClass(); $this->data->passwordHash = 'dbd014125a4bad51db85f27279f1040a'; } // Mock save functionality public function save() { // Store the data from $data back into the database } // Allow for changing a new password: public function setPassword($password) { $this->data->passwordHash = password_hash($password, self::HASH, ['cost' => self::COST]); } // Logic for logging a user in: public function login($password) { // First see if they gave the right password: echo "Login: ", $this->data->passwordHash, "\n"; if (password_verify($password, $this->data->passwordHash)) { // Success - Now see if their password needs rehashed if (password_needs_rehash($this->data->passwordHash, self::HASH, ['cost' => self::COST])) { // We need to rehash the password, and save it. Just call setPassword $this->setPassword($password); $this->save(); } return true; // Or do what you need to mark the user as logged in. } return false; } }
访客评论