后端密码加密与散列

时间:2016-04-27 14:03:43

标签: security authentication encryption hash

我对确保用户身份验证的最佳方式有疑问。

我遇到了一个加密 后端中的用户密码的Web应用程序。但是,使用相同密钥对所有密码进行加密。 此外,此密钥在后端是“硬编码”

他们(应用程序开发人员)声称这是非常安全的。不过我有疑虑。我相信这种方法可能会导致两个问题:

  • 加密密码的原因是为了避免在未经授权的数据库访问时访问密码。但是,如果您将密钥存储在同一服务器中,则他们也可以获得密钥。

  • 相同的密码会产生相同的加密值,因此攻击系统会更容易。

我的问题如下:

  • 我的说法是对的吗?如果真的那么不安全,我应该警告他们可能的威胁吗?

  • 使用hash + salt方法的优缺点是什么?

谢谢!

2 个答案:

答案 0 :(得分:4)

我不确定你是否可能错误地将加密和散列混合在一起。如果用户的密码是加密而不是哈希,那么攻击者有可能在数据泄露的情况下窃取所有用户密码。

在身份验证方面,您似乎有许多因素需要考虑。首先,任何散列都应该在后端完成,而不是在前端。在前端散列仍然容易受到哈希攻击。

一些开发人员采用双哈希方法,在前端对密码进行哈希处理,然后在后端重新哈希。我认为这是不必要的,前端密码应该由HTTPS层(TLS)覆盖,但是需要讨论。

首先,在解释如何安全地存储和验证用户之前,让我们先澄清两个关键术语。

加密

您指定用户的密码是加密的,而不是哈希。加密函数的作用是将输入(用户密码)以1对1的方式映射到输出(加密密码),这意味着可逆

这意味着如果黑客获得加密密钥(私钥)的访问权限,他们可以轻松地反转整个过程。

散列

相反,用户的密码应该是服务器端的哈希。为什么?因为您可以通过比较两个哈希来检查它们是否匹配,而无需存储该值的纯文本表示。

再一次,你可能会问,“为什么”?好吧,因为散列函数是单向的,这意味着纯文本值不能被反转(好吧,它们很难),我不会详细介绍。

我该怎么办?

用户密码绝不应以纯文本形式存储在Web服务器的任何部分。相反,您应该存储用户的哈希值。当用户尝试登录时,您通过HTTPS / TLS安全地接收其纯文本密码,对其进行哈希处理,如果两个哈希匹配,则对用户进行身份验证。

因此数据库表可能如此:

+--------------------------------------+
|  ID  |  Username  |   Password Hash  |       
+--------------------------------------+
|  1   | foo        | $2a$04$/JicM     |
|  2   | bar        | $2a$04$cxZWT     |
+--------------------------------------+
  • 注意,哈希是截断的BCrypt哈希值,有4轮(AKA - 无效)

现在让我们以Alice和我们的服务器为例。不要过于字面地获取数据。

Alice使用她的凭据发送登录请求,该凭据首先通过我们的安全传输层:

{username: "foo", password: "bar"} -> TLS() -> ZwUlLviJjtCgc1B4DlFnK -> | Server |

我们的服务器接收到它,然后使用它的证书密钥来解密它:

ZwUlLviJjtCgc1B4DlFnK -> KEY() -> {username: "foo", password: "bar"} -> Web Application

大!我们的凭据已经安全通过,现在是什么?哈希密码并与我们在数据库中得到的内容进行比较。

BCRYPT('bar') -> $2a$04$/JicM

if ($2a$04$/JicM == user.get_password_hash) {
    authenticate();
}
else {
    return status_code(401);
}

我们现在能够对用户进行身份验证,存储不可逆的哈希值,而不会存储纯文本值。这应该已经回答了你的第一个和第二个问题。

答案 1 :(得分:0)

是的,你的分析是正确的,这是不安全的。

任何正式审计肯定都会失败,例如: PCI-DSS。开发商/运营商可能认为这些账户提供的资产价值不大,因此他们没有必要提供这样的保护,但是他们仍然有责任照顾他们的客户 - 而且大多数人都会对不同的网站/服务使用相同的密码。

它确实为用户“恢复”密码提供了一种手段,而不会产生过期OTP的复杂性 - 但是邮寄明文密码会进一步破坏安全性。

实际上,即使攻击者只能访问加密的密码数据(特别是如果它包含已知的加密值/不使用初始化向量),也可以导出加密密钥。