PHP - 发送密码盐以进行哈希加密

3

我的数据库为每个用户存储唯一的盐值。

我正在为一个应用程序创建一个php登录脚本,其中每个用户都有自己独特的盐,并且这是我计划实现登录的方式。

  1. 用户输入详细信息并发送
  2. 用户名被发送,脚本检查它是否存在
  3. 如果存在,则返回该用户的盐,否则返回一般错误

我需要脚本返回该用户的盐,否则我的应用程序如何验证提交的密码是否正确,因为没有盐就不能散列密码并将其发送回来?

现在这里有一件事让我不确定。盐是否加密并不重要,因为黑客可以看到它并查看密码散列,可能还能做些什么。我应该在发送之前加密盐吗?

也许在下面的回复中我没有理解/忽略了某些东西。

请给出建议。


1
Nubcake,我问你为什么要通过某种不安全的通信传输盐。身份验证应始终在存储盐的位置进行。 - JRL
选择 id, user 从 users 表中,其中 stored_hash 等于 md5(concat(user_salt, $password)) 并且 username=$username。您可以在 select 语句中引用/使用给定记录中的其他字段。 - Marc B
实际的身份验证应尽可能靠近数据库进行。不要将哈希值和盐发送到客户端,然后让客户端对其密码进行哈希和比较。这是很糟糕的。将其密码发送到您的服务器并在那里进行哈希和比较。 - JRL
@Jon,我正在按照你说的做,即获取用户名和盐,但是你所说的“对密码进行哈希”,是什么意思?我在服务器端还没有它。 - Nubcake
@Nubcake,你可以选择公钥加密方案,将公钥嵌入应用程序中,私钥用于解密存储在服务器上。但即使使用标准连接,你仍然容易遭受中间人攻击,而这比起未经授权的身份验证更为普遍,因为你只通过数据库中的内容进行验证,这也会让你处于开放状态。如果安全对于你的应用至关重要,那么你需要在服务器上启用SSL。但是,用户密码的散列处理最好在服务端完成,以确保密码不以明文形式发送 [MORE]。 - Jon
显示剩余20条评论
1个回答

1
无论您的盐是散列还是明文字符串,重要的是使用盐可以防止直接使用字典/彩虹表攻击来暴力破解密码。另一个优点是每个用户都有不同的散列密码。
盐是在服务器端随机生成的字符串,不涉及与浏览器之间的任何传输。
在您的服务器上:
  // Password from form
  $pw = $_GET['password'];

  // Generate salt using unique values
  $salt = (rand(8).$registration_date.$username);

  // Password to be hashed
  $pwthb = ($pw.$salt);

如果黑客能够访问您的数据库,那么在大多数情况下,您的游戏已经结束了,因为您需要存储初始随机盐以进行哈希比较。
一个简单的例子:
1. 用户在注册时在浏览器中输入初始密码。 2. 在您的服务器上,将密码与唯一的盐组合,进行哈希处理并存储为DB中的密码。 3. 盐被存储在DB中。
注意:哈希可以使用PHP或使用MySQL/DB函数进行。
当用户返回时:
1. 用户在浏览器中输入密码。 2. 从DB中获取盐并与输入的密码组合。 3. 哈希密码+盐并与存储/哈希密码进行比较。 4. 如果匹配:进行身份验证。
就进一步阅读而言,建议查阅以下内容。

只是需要注意的一点,它不是“加密”,而是“散列”。加密意味着可以解密,而散列是“单向”的,不能被还原为原始部分。在处理用户密码时,这是一个微小但重要的区别。^^ - Jon
2
另一个小细节,如果你正确地进行哈希处理,即使获得了对数据库的访问权限,游戏也不会结束(使用bcrypt或者显著延长哈希时间,以便创建存储的哈希至少需要1-2秒)。生成进入数据库的哈希密码所需的计算时间越长,即使已知盐值,尝试暴力破解实际密码所需的时间也会更长。 - Jon
@jon 已经注意到了,只是试图保持简单。 - nickhar

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