如何安全存储用户密码?

Reb*_*bar 168 php security passwords salt password-hash

这比普通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]!";
}
Run Code Online (Sandbox Code Playgroud)

Jac*_*cco 267

确保密码存储方案安全的最简单方法是使用标准库.

因为安全性往往要复杂得多,并且比大多数程序员单独解决的问题更加隐形,所以使用标准库几乎总是最容易和最安全(如果不是唯一的)可用选项.


新的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';
}
Run Code Online (Sandbox Code Playgroud)

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


盐渍哈希改善:加入胡椒粉

如果你想要额外的安全性,安全人员现在(2017)建议在(自动)盐渍密码哈希中添加" 辣椒 ".

有一个简单的,可以安全地实现这种模式的类,我推荐: Netsilik/PepperedPasswords (github).
它附带一个MIT许可证,因此您可以随意使用它,即使在专有项目中也是如此.

代码示例使用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';
}
Run Code Online (Sandbox Code Playgroud)


OLD标准库

请注意:您不应该再需要它了!这只是出于历史目的.

看看:便携式PHP密码哈希框架:phpass并确保CRYPT_BLOWFISH尽可能使用算法.

使用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';
}
Run Code Online (Sandbox Code Playgroud)

PHPass已经在一些众所周知的项目中实现:

  • .中文
  • WordPress 2.5+以及bbPress
  • Drupal 7发布,(可用于Drupal 5和6的模块)
  • 其他

好消息是你不需要担心细节,这些细节已经由有经验的人编程,并由互联网上的许多人审查.

有关密码存储方案的更多信息,请阅读Jeff的博客文章:您可能错误地存储密码

无论你做什么,如果你去' 我会自己做,谢谢 '的方法,不要使用MD5SHA1再也没有.它们是很好的散列算法,但出于安全考虑认为是破坏的.

目前,使用crypt,使用CRYPT_BLOWFISH是最佳实践.
PHP中的CRYPT_BLOWFISH是Bcrypt哈希的实现.Bcrypt基于Blowfish分组密码,利用它昂贵的密钥设置来减慢算法速度.


Ant*_*lev 29

如果您使用参数化查询而不是连接SQL语句,那么您的用户将更安全.和应该是每个用户唯一的,应与密码哈希一起存储.

  • Nettuts +是一个非常糟糕的文章用作模型 - 它包括使用MD5,即使用盐也可以很容易地强制使用.相反,只需使用PHPass库,它比您在教程网站上找到的任何代码都要好得多,即这个答案:http://stackoverflow.com/questions/1581610/how-can-i-store-my-用户,密码,安全/ 1581919#1581919 (3认同)

R S*_*hko 11

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

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

更好的方法是每次用户更改密码时,系统会生成随机盐并将该盐与用户记录一起存储.这使得检查密码成本更高一些(因为您需要在生成MD5签名之前查找盐),但这使得攻击者更难以预生成MD5.

  • 盐通常与密码哈希一起存储(例如`crypt()`函数的输出).而且由于您无论如何都必须检索密码哈希,因此使用特定于用户的盐不会使该过程变得更加昂贵.(或者你的意思是生成一个新的随机盐是昂贵的?我真的不这么认为.)否则+1. (3认同)

aki*_*irk 11

随着PHP 5.5(我所描述的甚至早期版本可用,见下文)我想建议使用其新的内置解决方案: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));
?>
Run Code Online (Sandbox Code Playgroud)

将返回

string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
Run Code Online (Sandbox Code Playgroud)

如您所见,字符串包含salt以及选项中指定的成本.它还包含使用的算法.

因此,在检查密码时(例如,当用户登录时),当使用补充password_verify()功能时,它将从密码散列本身提取必要的加密参数.

当不指定salt时,生成的密码哈希在每次调用时都会有所不同,password_hash()因为salt是随机生成的.因此,将先前的哈希与新生成的哈希进行比较将失败,即使是正确的密码也是如此.

验证这样的作品:

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.'));
Run Code Online (Sandbox Code Playgroud)

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

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

  • 在大多数情况下,最好省略salt参数.该函数从操作系统的随机源创建一个salt,您可以自己提供更好的盐. (2认同)