使用PHP和MySQL对我的哈希值进行加盐处理

10

像大多数用户一样,我只是试图找出一种安全的密码存储方式。在这里我没有找到(或者可能是因为我理解不够)如何从数据库中检索含有独特盐值的哈希值,并将其与散列密码分离的方法,尤其是当每个密码都有唯一盐值而同时需要将盐值和密码存储在一个单独的列中。

我发现了许多加密密码的好方法(如SHA-256),但是不确定如何存储和检索密码,尤其是在PHP手册中找不到相关信息。

到目前为止,这是我所理解的:

SHA('$salt'.'$password') // My query sends the password and salt 
                         // (Should the $salt be a hash itself?)

在那之后,我对盐一无所知。

没有盐的情况下检索密码很容易,但是盐困扰着我。我从哪里获取 $salt 的值,尤其是如果它是唯一且安全的?我需要将它们隐藏在另一个数据库中吗?常数(似乎不安全)?

编辑:HMAC 中的关键变量应该是 salt 还是其他什么东西?


值得一提的是,构建了SSL支持的MySQL 5.5包括一个SHA2()函数,提供SHA224、SHA256、SHA384和SHA512哈希算法。如果您使用的是早期版本的MySQL,请在PHP中使用hash()函数。 - Bill Karwin
再次感谢你的帮助,比尔。这已经是第二次了!我使用的是5.1版,因为它随WAMP(wampserver.com)一起提供。我不得不卸载旧版MySQL才能安装这个版本。不幸的是,我不确定如何更新它……我会尝试使用PHP进行加密。 - Tarik
2个回答

5

首先,你的数据库管理系统(MySQL)不需要支持密码哈希。你可以在PHP端完成所有操作,这也是你应该做的。

如果你想要将盐和哈希值存储在同一列中,你需要将它们连接起来。

// the plaintext password
$password = (string) $_GET['password'];

// you'll want better RNG in reality
// make sure number is 4 chars long
$salt = str_pad((string) rand(1, 1000), 4, '0', STR_PAD_LEFT);

// you may want to use more measures here too
// concatenate hash with salt
$user_password = sha512($password . $salt) . $salt;

现在,如果您想验证密码,可以执行以下操作:
// the plaintext password
$password = (string) $_GET['password'];

// the hash from the db
$user_password = $row['user_password'];

// extract the salt
// just cut off the last 4 chars
$salt = substr($user_password, -4);
$hash = substr($user_password, 0, -4);

// verify
if (sha512($password . $salt) == $hash) {
  echo 'match';
}

你可能想看看phpass,它也使用了这种技术。它是一个PHP哈希解决方案,其中使用了一些其他的技术,比如盐值。

你绝对应该看一下WolfOdrade链接的答案。


谢谢!有很多新的功能,但是我可以自己弄清楚细节。这正是我正在寻找的。我以前从未听说过"subtract string"功能,这个非常有帮助。是否可能从字符串的前面减去不同的部分?再次感谢! - Tarik
谢谢。我尝试了hash_hmac,但是在比较登录密码和数据库密码时遇到了问题。 hash_hmac中的salt是随机生成的,那我如何减去它呢?我还注意到您的示例中也有相同的情况。 sha512($ password . $ salt)正在散列密码和唯一盐。我该如何获取该唯一盐以将输入的密码与数据库密码哈希化?抱歉问了这么多问题,我就差一点了! - Tarik
在我的例子中,盐和密码一起存储。这使您可以在检查哈希之前将两者分开。hash_hmac基本上是创建加盐密码的更复杂的方法。在WolfOdrade的链接中,他们建议使用由每个用户nonce(如我的4个字母盐)和全局应用程序可访问的“站点密钥”组成的盐(因此受损的数据库不会 compromise盐)。这两个连接将是hash_hmac函数的$key参数。 - igorw
每个用户的nonce是我遇到的问题。它不是唯一的,但重复非常罕见。就像你的例子一样,我有一个随机数,但有10位数字和填充使用随机字符,然后将其哈希为盐并添加到hmac中。我只是无法理解我应该在哪里保留这些每个用户的盐,但在同一列中。在WoflOrdade的链接中,他在字符串之间使用冒号,但我在我的哈希中找不到任何冒号,所以我不知道它们如何帮助。 - Tarik
此外,我不知道hash_hmac如何将字符串哈希在一起。但无论如何,我怎么知道我减去的量足够去除盐以进行验证?因为我看到$salt从哈希中获取数据,那么这是否意味着它正在获取已经哈希过的数字?那么将已经哈希过的数字与用户密码组合会产生哈希吗? - Tarik
显示剩余3条评论

0

个人建议使用MySQL的内置函数来完成此操作。

我通常会在数据库配置文件中创建一个函数,返回一个密钥字符串。配置文件应该位于站点根目录之外,以便Web服务器可以访问该文件但其他人无法访问。例如:

function enc_key(){
     return "aXfDs0DgssATa023GSEpxV";
}

然后在你的脚本中使用它与MySQL中的SQL查询、AES_ENCRYPT和AES_DECRYPT函数,像这样:

require_once('dbconf.inc.php');

$key = enc_key();

//When creating a new user
$sql = "INSERT INTO users (username, password) VALUES ('bob', AES_ENCRYPT('{$key}', {$password}))";

//When retrieving users password
$sql = "SELECT AES_DECRYPT('{$key}', password) AS password FROM users WHERE username like 'bob'";

这真的不是一个好主意。你不应该加密密码,而应该使用哈希(如果有人黑掉了你的服务器,他将完全访问所有用户的密码)。你还暗示了 SQL 注入,因为没有转义。 - igorw
首先,我意识到那里的字符串容易受到 SQL 注入攻击;然而这不是讨论的主题。SQL 语句只是示例,我假设他们意识到需要对用户输入进行清理。我在这里不是为他们编写应用程序,而是回答具体问题。 - Kelly Copley
第二,只要保管好密钥,双向加密和“哈希”一样安全。我意识到如果有人入侵您的服务器,他们会获取到密码,但是如果有人入侵您的服务器,他们可以访问所有内容,包括数据库中的其他信息,因此哈希密码似乎变得无关紧要了,您觉得呢? - Kelly Copley
如果有人获取了您的密钥(例如:SQL注入破坏了查询,导致错误消息暴露失败的查询),并且获得了加密密码,则很容易获取所有明文密码。如果使用哈希值,这将是不可能的。 - igorw
1
如果您使用输入密码作为加密密钥进行加密,则双向加密足够安全,因为密钥永远不会被存储。 - user1193509

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接