PHP在将密码存储到数据库之前对其进行加密


PHP encrypt password before storing it to database

我在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'时,这才是真的。