PHP 用于服务器端开发,在构建登录和注册过程时需要密码。出于安全目的和隐私问题,我们需要对我们的密码进行哈希处理,这样任何人(包括你和你的数据库管理员)都无法知道用户的密码。
但是,当我们对密码进行哈希处理时,当我们想登录时,我们需要对其进行重新哈希处理。本文详细介绍了密码哈希处理以及如何使用 PHP 内置函数 password_hash()
和 password_verify()
.
[PHP 中的密码哈希]
从用户那里收集的数据存储在数据库中,任何有权访问数据库的人都可以看到这些数据。用户名和地址通常保持原样;它们不如你帐户的密钥重要。
作为用户密码的文本字符串通过散列算法(bcrypt、md5、sha-1、sha-2)传递,以防止按原样保存密码并创建文本的加扰表示。密码的这个加扰表示被存储,并且在登录过程中,加扰表示被比较。
内置的 password_hash()
函数使用 bcrypt 算法,这是 Auth0 推荐的 并用于其客户群。此外,password_verify()
函数将密码文本与哈希值进行比较,并在密码与哈希值匹配时返回布尔值。
[在 PHP 中使用 password_hash()
和 password_verify()
进行密码散列]
当用户访问你的站点并创建一个新帐户时,作为 PHP 开发人员,你将确保你的应用程序对密码进行哈希处理。为此,我们应用 password_hash()
函数。
<?php $password = "24FE21121@1*?"; // password the user imputs. echo password_hash($password, PASSWORD_DEFAULT); // outputs the hashed password ?>
代码片段的输出是:
$2y$10$YRmyqWGiHbDSI31XbD2DuOzmTKSjYSSgR.2.3rYCmSSFS/xlAtb3.
代码片段使用默认散列算法,根据 PHP 文档,该算法使用 bcrypt 算法。如果我们打算改变散列算法,我们可以改变函数的第二个参数。
我们可以使用其他三个可能的参数(散列算法)。PASSWORD_BCRYPT
、PASSWORD_ARGON2I
和 PASSWORD_ARGON2ID
是支持的参数。
PASSWORD_BCRYPT
使用 CRYPT_BLOWFISH
算法,PASSWORD_ARGON2I
使用 Argon2i
散列算法,而 PASSWORD_ARGON2ID
使用 Argon2id
散列算法。要更好地了解每种算法的工作原理,请查看 PHP 密码哈希文档。
让我们在我们的代码中尝试 PASSWORD_BCRYPT
参数。
<?php $password = "24FE21121@1*?"; // password the user imputs. echo password_hash($password, PASSWORD_DEFAULT); // outputs the hashed password ?>
代码片段的输出是:
$2y$10$vNfovWay8hSq5ixa/lOPK.4YMVX1kgYCBPDEdvz3zM/EBUiBUukpO
PASSWORD_DEFAULT
和 PASSWORD_BCRYPT
都使用 $2y$
标识符,并将生成 60 个字符的字符串。通过上述过程,我们成功地对用户的密码进行了哈希处理。
现在,如果用户想登录他的帐户,我们需要将他们输入的密码与散列密码进行比较。这就是 password_verify()
发挥作用的地方。
我们可以将密码和存储的哈希密码与内置函数进行比较。
<?php $password = "24FE21121@1*?"; $hashed_password ='$2y$10$YRmyqWGiHbDSI31XbD2DuOzmTKSjYSSgR.2.3rYCmSSFS/xlAtb3.'; print_r(password_verify($password, $hashed_password)); ?>
代码片段的输出是:
1
在 PHP 中,1 代表真
,0 代表假
。
让我们对由 PASSWORD_BCRYPT
参数生成的散列密码尝试 password_verify()
函数。
<?php $password = "24FE21121@1*?"; $hashed_password = '$2y$10$vNfovWay8hSq5ixa/lOPK.4YMVX1kgYCBPDEdvz3zM/EBUiBUukpO'; print_r(password_verify($password, $hashed_password)); ?>
代码片段的输出是:
1
无论我们使用什么散列密码,password_verify()
函数都可以工作的原因是因为该函数验证与 crypt()
兼容的给定散列匹配,两者兼而有之。此外,这些函数将算法、成本和盐作为返回哈希的一部分返回,并且可以安全地抵御计时攻击。
要改善你的哈希结果,请在 password_hash()
函数中指定成本和盐选项。但是,如果你不了解如何使用它,它会极大地影响你的安全。
要检查 password_verify()
函数是否会捕获错误密码,让我们输入一个错误密码(从 24FE21121@1*?
更改为 24Fqqw1121@1*?
)。
<?php $password = "24Fqqw1121@1*?"; $hashed_password = '$2y$10$vNfovWay8hSq5ixa/lOPK.4YMVX1kgYCBPDEdvz3zM/EBUiBUukpO'; if (password_verify($password, $hashed_password)) { echo "Password Matches!"; } else { echo "Wrong Password"; } ?>
代码片段的输出是:
Wrong Password
如果我们在实际登录过程的上下文中使用它,代码可能如下所示:
<?php $connect = mysqli_connect($localhost, $username, $password, $database); if (isset($_POST['submit'])) { extract($_POST); // retrive stored hashed password $sqlQuery = mysqli_query($connect, "SELECT * FROM USERTABLE WHERE USER='$username'"); $fetch = mysqli_fetch_array($sqlQuery); $currentPassword = $fetch['hashPassword']; if (password_verify($enteredPassword, $currentPassword)) { // password matches $_SESSION['id'] = $fetch['id']; header("location: home.php"); } else { // password doesn't match $output = "Wrong Passworfd"; } }