这比普通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]!";
}
答案 0 :(得分:265)
确保密码存储方案安全的最简单方法是使用标准库。
因为安全性往往要复杂得多,并且比大多数程序员单独解决的问题更加隐形,所以使用标准库几乎总是最简单,最安全(如果不是唯一的)可用选项。
如果您使用的是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)建议在(自动)加密的密码哈希中添加“pepper”。
有一个安全实现此模式的简单类,我建议:
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';
}
请注意:你不应再需要这个了!这只是出于历史目的。
请查看:Portable PHP password hashing framework: 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';
}
PHPass已在一些众所周知的项目中实施:
好消息是你不需要担心细节,这些细节是由有经验的人编制的,并且已经被互联网上的许多人评论过。
有关密码存储方案的更多信息,请阅读Jeff的博文:You're Probably Storing Passwords Incorrectly
无论你做什么,如果你去'我会自己做,谢谢'方法,不再使用MD5
或SHA1
< / strong>即可。它们是很好的散列算法,但出于安全目的而被视为被破坏。
目前,使用crypt和CRYPT_BLOWFISH是最佳做法 PHP中的CRYPT_BLOWFISH是Bcrypt哈希的实现。 Bcrypt基于Blowfish分组密码,利用它昂贵的密钥设置来减慢算法速度。
答案 1 :(得分:28)
如果您使用参数化查询而不是连接SQL语句,那么您的用户会更安全。 the salt对每个用户都应该是唯一的,并且应该与密码哈希一起存储。
答案 2 :(得分:11)
更好的方法是让每个用户拥有独特的盐。
拥有盐的好处是它使攻击者更难以预先生成每个字典单词的MD5签名。但是如果攻击者得知您有固定的盐,那么他们就可以预先生成每个字典单词的MD5签名。前缀为固定盐。
更好的方法是每次用户更改密码时,系统会生成随机盐并将该盐与用户记录一起存储。这使得检查密码成本更高一些(因为您需要在生成MD5签名之前查找盐),但这会使攻击者更难以预生成MD5。
答案 3 :(得分: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));
?>
将返回
string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
正如您所看到的,该字符串包含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.'));
我希望提供这些内置函数可以在数据被盗时提供更好的密码安全性,因为它减少了程序员必须投入适当实现的思路。
有一个小型库(一个PHP文件),它将在PHP 5.3.7 +中为您提供PHP 5.5的password_hash
:https://github.com/ircmaxell/password_compat
答案 4 :(得分:0)
这对我很好。阿特伍德先生写了一篇关于the strength of MD5 against rainbow tables的文章,基本上用了很长的盐,就像你坐得很漂亮(尽管有一些随机的标点/数字,它可以改善它)。
你也可以看看SHA-1,这些日子似乎越来越受欢迎。
答案 5 :(得分:0)
我想补充一下:
为了与旧系统兼容,通常会设置密码最大长度的限制。这是一个糟糕的安全策略:如果设置限制,则仅将其设置为最小密码长度。
要恢复忘记的密码,您应该发送用户可以更改密码的地址。
密码哈希可能已过期(可能会更新算法的参数)。通过使用函数password_needs_rehash()
,您可以查看它。