如何安全地存储我的用户密码?

这比普通的MD5更安全吗? 我刚开始研究密码安全。 我很新的PHP。

$salt = 'csdnfgksdgojnmfnb'; $password = md5($salt.$_POST['password']); $result = mysql_query("SELECT id FROM users WHERE username = '".mysql_real_escape_string($_POST['username'])."' AND password = '$password'"); if (mysql_num_rows($result) < 1) { /* Access denied */ echo "The username or password you entered is incorrect."; } else { $_SESSION['id'] = mysql_result($result, 0, 'id'); #header("Location: ./"); echo "Hello $_SESSION[id]!"; } 

使密码存储scheme安全的最简单方法是使用标准库

由于安全性往往比起大多数程序员可以单独解决的情况更复杂,并且具有更多无形的可能性,所以使用标准库几乎总是最简单和最安全(如果不是唯一的话)可用选项。

新的PHP密码API(5.5.0+)

如果您使用PHP 5.5.0或更高版本,则可以使用新的简化密码散列API

使用PHP密码API的代码示例:

 <?php // $hash is what you would store in your database $hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]); // $hash would be the $hash (above) stored in your database for this user $checked = password_verify($_POST['password'], $hash); if ($checked) { echo 'password correct'; } else { echo 'wrong credentials'; } 

(如果您仍在使用旧版本5.3.7或更高版本,则可以安装ircmaxell / password_compat以访问内置函数)

加盐腌后改进:加胡椒粉

如果您想要额外的安全性,安全人员现在(2017年)build议在(自动)腌制的密码哈希中添加一个“ 胡椒 ”。

有一个简单的,安全地实现这个模式的类,我推荐: Netsilik / PepperedPasswords ( github )。
它带有麻省理工学院许可证,所以即使在专有项目中,您也可以使用它。

使用Netsilik/PepperedPasswords的代码Netsilik/PepperedPasswords

 <?php use Netsilik/Lib/PepperedPasswords; // Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper). $config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF'); $hasher = new PepperedPasswords($config['pepper']); // $hash is what you would store in your database $hash = $hasher->hash($_POST['password']); // $hash would be the $hash (above) stored in your database for this user $checked = $hasher->verify($_POST['password'], $hash); if ($checked) { echo 'password correct'; } else { echo 'wrong credentials'; } 

旧的标准库

请注意:你不应该再需要这个了! 这仅仅是为了历史的目的。

看看: 便携式PHP密码哈希框架phpass ,并确保您尽可能使用CRYPT_BLOWFISHalgorithm。

使用phpass的代码示例(v0.2):

 <?php require('PasswordHash.php'); $pwdHasher = new PasswordHash(8, FALSE); // $hash is what you would store in your database $hash = $pwdHasher->HashPassword( $password ); // $hash would be the $hash (above) stored in your database for this user $checked = $pwdHasher->CheckPassword($password, $hash); if ($checked) { echo 'password correct'; } else { echo 'wrong credentials'; } 

PHPass已经在一些相当知名的项目中实现了:

  • 。中文
  • WordPress 2.5+以及bbPress
  • Drupal 7版本(可用于Drupal 5和6的模块)
  • 其他

好的是,你不需要担心细节,这些细节是由有经验的人编写的,并经过互联网上的许多人的审查。

有关密码存储scheme的更多信息,请阅读Jeff的博客文章: 您可能正确存储密码

无论你做什么,如果你去' 我会自己做,谢谢 '的方法, 不要再使用MD5SHA1 。 它们是很好的散列algorithm,但是出于安全目的而被认为是破碎的

目前,使用crypt ,CRYPT_BLOWFISH是最好的做法。
PHP中的CRYPT_BLOWFISH是Bcrypt哈希的实现。 Bcrypt基于Blowfish分组密码,利用昂贵的密钥设置来降低algorithm速度。

如果使用参数化查询而不是连接SQL语句,用户将会更安全。 盐对于每个用户应该是唯一的,并且应该与密码哈希一起存储。

一个更好的方法是每个用户有一个独特的盐。

有一个盐的好处是,它使得攻击者更难预先生成每个字典单词的MD5签名。 但是如果攻击者知道你有一个固定的盐,他们就可以预先生成以固定盐为前缀的每个字典单词的MD5签名。

更好的方法是每次用户更改密码时,系统会随机生成一个盐并将该盐与用户logging一起存储。 这使得检查密码变得更加昂贵(因为在生成MD5签名之前需要查找salt),但是攻击者预先生成MD5会更困难。

使用PHP 5.5(我所描述的可用于甚至更早的版本,见下文),我想build议使用其新的内置解决scheme: password_hash()password_verify() 。 它提供了几个选项,以达到您需要的密码安全级别(例如,通过$options数组指定一个“cost”参数)

 <?php var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT)); $options = array( 'cost' => 7, // this is the number of rounds for bcrypt // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended ); var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options)); ?> 

将返回

 string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK." string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d." 

您可能会看到,该string包含盐以及在选项中指定的成本。 它还包含使用的algorithm。

因此,在检查密码(例如用户login时)时,如果使用免费的password_verify()函数,它将从密码哈希本身提取必要的密码参数。

当不指定salt时,每次调用password_hash()时生成的密码哈希将会不同,因为盐是随机生成的。 因此,比较以前的散列与新生成的散列将失败,即使对于一个正确的密码。

validation这样的作品:

 var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K')); var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K')); var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.')); var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.')); 

我希望提供这些内置的函数将很快提供更好的密码安全性,以防数据被盗用,因为它减less了程序员必须投入适当的实现的思想量。

有一个小型库(一个PHP文件),它会在PHP 5.3.7+中为您提供PHP 5.5的password_hash : https : //github.com/ircmaxell/password_compat

这对我来说没问题。 Atwood先生写了关于MD5对彩虹桌的强度 ,基本上是用一个很长的盐,就像你坐得漂亮(虽然有一些随机的标点/数字,可以改善它)。

你也可以看看SHA-1,这些日子似乎越来越受欢迎。

我想补充一下:

  • 不要限制用户密码的长度

为了与旧系统兼容,通常设置密码的最大长度限制。 这是一个不好的安全策略:如果您设置了限制,请仅为最小​​密码长度进行设置。

  • 不要通过电子邮件发送用户密码

为了恢复被遗忘的密码,您应该发送用户可以更改密码的地址。

  • 更新用户密码的哈希值

密码散列可能已过时(algorithm的参数可能会更新)。 通过使用函数password_needs_rehash()你可以检查出来。