我在php.net上找到了下面的例子,在存储密码之前保护密码。但是,我不太理解第3行。有人能解释一下吗?谢谢
1 <?php
2 $password = crypt('mypassword'); // let the salt be automatically generated
3 if (crypt($user_input, $password) == $password) {
4 echo "Password verified!";
5 }
6 ?>
crypt是一个单向函数,返回一个已经包含盐的字符串
当将用户输入与密码结果进行比较时,函数会自动从字符串中提取salt。
更清楚的是:
crypt()输出一个字符串,该字符串包含salt和哈希结果。当您将该字符串作为salt传递给它时,它知道只提取salt部分而忽略hash部分。它仍然返回一个同时包含salt和hash的字符串。所以这些字符串可以进行比较
您可以通过以下方式清楚地理解:
当用户第一次注册时,流程为:
$password = crypt($user_input); // let the salt be automatically generated
if (crypt($user_input, $password) == $password) {
echo "Password verified!";
}
当用户尝试登录时,过程将是:
if(crypt($user_passsword_currentlyin_db, $user_inputted_password) == $user_inputted_password) {
echo "Password verified!";
}
希望你得到东西:)
编辑:
密码的输出包括:
当您将此输出作为"salt"传递回crypt时,它将提取正确的算法和salt,并将它们用于操作。如果只提到一个算法,它会使用这个算法并生成随机盐。否则,它将选择默认算法并生成随机盐。忽略传递的salt参数中的哈希部分。
因此,您可以简单地将stored_hash与crypt(password,stored_hash)进行比较——如果相等,则很可能是正确的密码。
以下是crypt如何工作的伪代码解释(类似PHP语法):
function crypt($password, $salt)
{
if (substr($salt,0 1) == "_") {
$count = substr($salt, 1, 4);
$real_salt = substr($salt, 5, 4);
return "_" . $count . $real_salt . crypt_ext_des($password, $count, $salt);
}
if(substr($salt, 0, 3) == "$1$") {
list($ignored, $real_salt, $ignored) = explode("$", $salt);
return "$1$" . $real_salt . "$" . crypt_md5($password, $real_salt);
}
if(substr($salt, 0, 4) == "$2a$") {
$cost = substr($salt, 4, 2);
$real_salt = substr($salt, 7, 22);
return "$2a$" . $cost . "$" . $real_salt . crypt_brypt($password, $real_salt, $cost);
}
// ... SHA256 and SHA512 analogons
// no match => STD_DES
$real_salt = substr($salt, 0, 2);
return $real_salt . crypt_std_des($password, $real_salt);
}
最好不要在服务器端存储纯文本密码,以防密码文件被泄露和用户密码泄露。
相反,当用户注册时,在将密码存储在数据库中之前,应该对其使用单向哈希算法。这样,如果文件被泄露,就不可能重现用户的密码。
当用户登录时,无法将他们刚刚输入的明文密码与数据库中的明文密码进行比较,因为数据库中的密码已被散列。
然而,由于散列函数的相同输入总是会产生相同的输出,第3行将对用户刚刚输入的明文输入进行散列,并将其与数据库中存储的散列进行比较。通过这种方式,您可以将哈希与哈希进行比较,并可以确定用户是否经过了身份验证。
关于安全性的几个注意事项:你应该始终保持故障安全,所以你的代码应该是:
if(crypt($user_input, $password) == $password) {
echo "Password verified!";
} else { die("Wrong username/password"); }
还需要注意的是,可以使用彩虹表重建受损的密码文件。
$user_input只不过是存储在DATABASE 中的密码
if(crypt($stored_passsword_in_db, $current_password) == $current_password) {
echo "Password verified!";
}
希望这能帮助你。。。。
第二个参数是关键。它要么什么都不接受,要么接受salt,要么接受crypt
之前生成的hash,该hash中嵌入了用于生成hash的salt。在后一种情况下,使用的是盐,而不是整个哈希。因此,这一点成立(确保你理解这一点,因为这是理解第3行的关键):
crypt($input, $salt) == crypt($input, crypt($input, $salt))
你在数据库中的用户散列密码,是这个等式中的左项。因此,第3行可以重写为:
if (crypt($user_input, crypt('mypassword')) == crypt('mypassword'))
盐是在第2行自动生成的,假设它等于"autosalt"。第3行现在可以重写为:
if (crypt($user_input, crypt('mypassword', 'autosalt')) == crypt('mypassword', 'autosalt')
这样:只有当$user_input == 'mypassword'
时,这才是真的。