比较散列密码

问题描述 投票:0回答:1

最佳实践建议我存储经过哈希处理和加盐处理的密码。我已经知道了。我的问题是:如何提供清晰且安全的机制来检查密码(其哈希值)?

我们有一个 CLI 客户端,用户可以在其中输入纯密码。 CLI 客户端是远程计算机上的独立应用程序。我可以散列密码并发送给后端,后端应该检查凭据(还有用户权限)。但: a) Spring 安全编码器(PBKDF2、Argon2、Bcrypt、Scrypt 等)每次都会给我不同的哈希值,这是显而易见的,因为盐也是随机的。 “静态”盐可以解决这个问题:一旦创建了用户,盐就存储在数据库中,我可以用它来散列密码。 b) 中间人可以发送相同的正确哈希值,该哈希值将与存储在数据库中的进行比较 c) 向 CLI(或“静态”用户盐)客户端提供额外的数据库交互会破坏其目的和架构。 CLI 除了地址和端口之外,对后端一无所知

有办法吗?或者参考最佳安全实践应该如何完成? 预先感谢。

java security spring-security
1个回答
0
投票

当您对密码进行哈希处理时,您不会将哈希值发送到验证身份的事物(我们称之为“身份验证器”),即,如果您的身份验证器实现为(伪代码):

String dbHash = db.select(
  "SELECT passHash FROM users WHERE username = ?", req.getParam("username"));
String inHash = req.getParam("passHash");
if (!dbHash.equals(inHash)) throw new NotAuthorizedException();
return; // user is authenticated

您发送实际密码。然后你让验证器完成对其进行哈希处理的工作 - 这会起作用,因为这大致就是 passhash 验证算法的工作原理:

String dbHash = db.select("SELECT passHash FROM users WHERE username = ?", username);
String[] parts = dbHash.split("::");
String salt = parts[0];
String storedHash = parts[1];

String userSuppliedHash = applyBCrypt(salt, userSuppliedPassword);
if (!userSuppliedHash.equals(storedHash)) throw new NotAuthorizedException();
return; // user is authenticated

您应该复制该功能。这就是‘标准’。

现在,“标准”有问题。它不能保护用户免受受感染服务器的侵害 - 受感染服务器会获取实际密码。用户可以在某种程度上防止这种情况 - 不要重复使用密码。如果服务器受到损害,那么用户将在该服务器上执行的任何操作也会受到损害。这也意味着攻击者必须不断地攻击该服务器(与直接存储原始密码相反,在这种情况下,黑客只需要单个数据库转储)。

这个问题是有解决办法的。它们不涉及转移找出盐和应用哈希的责任。一般来说,如果您想比明显的方案进一步进行身份验证(即:仅发送这些密码纯文本 - 见下文),您完全放弃密码并使用密钥文件(并且客户端可以自由地使用任何完全加密其私钥)如果需要的话,基于客户端密码的方案)。和/或将身份验证转变为质询/响应方案。例如:

  • 用户从服务器请求登录,只需发送用户名。
  • 服务器汇总一个大的随机数。它将这个号码发送给客户端。客户端和服务器都执行:HASH(CONCAT(随机数,密码))。客户端发送这个。服务器验证这一点。这样,受感染的服务器可以进行中间人攻击,但无法恢复密码。

有很多这样的方案,但它们很少用于基于表单的 Web 登录。查看 OAuth 和朋友。他们对这件事进行了深思熟虑。

明文???

是的,当然,这是一个大问题。但是你不能通过让客户端执行哈希来解决这个问题(这将涉及客户端向服务器询问盐,或者使用静态盐,这本身就有很大很大的问题,不要这样做1),因为现在哈希值实际上是密码,而您......仍在发送该明文。

解决方案是使用安全的通信通道。不安全,如“我们知道用户已通过身份验证” - 安全,如“通道已加密”。例如,https 不是(除非您使用客户端证书;我建议不要这样做)身份验证机制。但它确实提供了一个安全通道。


[1] 如果站点存储所有哈希密码,但使用静态哈希,我只需扫描最常见的哈希值。这将是

iloveyou
abc123
或其他“最常用的 5 个密码”之一。我现在立即知道每个具有通用密码的用户的密码。这不好。通过正确的实现(其中每个密码哈希都有自己的盐),没有什么办法,但对于黑客来说,只需尝试
iloveyou
作为每个帐户的密码并祈祷其正确。这仍然会给他们带来大量帐户,但至少他们必须对所有内容执行 ping 操作,而不是事先知道哪些帐户具有该密码。

© www.soinside.com 2019 - 2024. All rights reserved.