使用密码与哈希加密密码
Encrypting password with password vs Hashing
我正在为我们的内部工具之一构建身份验证服务,在查看各种文章后,我可以将它们总结为
- 不使用加密,因为一旦遭到破坏,私钥可能会危及一切。
- 使用加盐的散列来存储散列并简单地比较散列。这样,即使哈希值被泄露,也无法获取实际密码。
我知道任何可能导致明文密码的东西都是不好的,但我只是想知道为什么没有人使用密码来加密密码,比如 AES256
?我的意思是,因为它是对称加密,所以它没有任何私钥。因此,即使发生泄露,也无法取回实际密码。对密码加盐并用密码本身加密有什么问题?
What's wrong with salting the password and encrypting it with the password itself?
这是一个非常快速的操作,可以非常快速地测试密码(即 "cracked")。使用像 SHA-2 这样的算法进行简单散列也是如此。处理密码的正确方法是加盐并拉伸它们(而不是简单地散列它们)。 "Stretching" 意味着 运行 通过一种称为 KDF(密钥派生函数)的耗时算法(例如 PBKDF2 或 scrypt)将它们连接起来。
同样重要的是,无论如何,人工生成的密码不能直接用于 AES 加密。 AES 需要精确大小(16、24 或 32 字节)的密钥,并且为了安全起见,密钥在整个密钥空间中应该是完全随机的。人为生成的密码很少有正确的长度,并且在整个密钥空间中都不是随机的(既因为人类是糟糕的随机值生成器,又因为 32 个可键入的字符是所有可能的 32 字节密钥的微不足道的一部分;要正确键入这样的密钥, "password" 需要将近 40 个字符长,并且使用所有 upper/lowercase、数字和符号在通用键盘上完全随机输入。
将人工生成的密码转换为密钥的正确方法是 运行 通过 KDF(这就是它被称为 "key derivation function" 的原因)。如果您只关心身份验证(验证用户知道正确的密码),那么添加额外的加密步骤就没有任何价值。您可以只使用拉伸键。
扩展密码(KDF 的输出)是唯一应该发送到服务器的东西。然后服务器应使用 SHA-2 对该值再进行一次哈希处理并存储它。这样,呈现给服务器的密钥就与存储在数据库中的密钥不同,即使数据库被盗,也无法用于向服务器进行身份验证。
我正在为我们的内部工具之一构建身份验证服务,在查看各种文章后,我可以将它们总结为
- 不使用加密,因为一旦遭到破坏,私钥可能会危及一切。
- 使用加盐的散列来存储散列并简单地比较散列。这样,即使哈希值被泄露,也无法获取实际密码。
我知道任何可能导致明文密码的东西都是不好的,但我只是想知道为什么没有人使用密码来加密密码,比如 AES256
?我的意思是,因为它是对称加密,所以它没有任何私钥。因此,即使发生泄露,也无法取回实际密码。对密码加盐并用密码本身加密有什么问题?
What's wrong with salting the password and encrypting it with the password itself?
这是一个非常快速的操作,可以非常快速地测试密码(即 "cracked")。使用像 SHA-2 这样的算法进行简单散列也是如此。处理密码的正确方法是加盐并拉伸它们(而不是简单地散列它们)。 "Stretching" 意味着 运行 通过一种称为 KDF(密钥派生函数)的耗时算法(例如 PBKDF2 或 scrypt)将它们连接起来。
同样重要的是,无论如何,人工生成的密码不能直接用于 AES 加密。 AES 需要精确大小(16、24 或 32 字节)的密钥,并且为了安全起见,密钥在整个密钥空间中应该是完全随机的。人为生成的密码很少有正确的长度,并且在整个密钥空间中都不是随机的(既因为人类是糟糕的随机值生成器,又因为 32 个可键入的字符是所有可能的 32 字节密钥的微不足道的一部分;要正确键入这样的密钥, "password" 需要将近 40 个字符长,并且使用所有 upper/lowercase、数字和符号在通用键盘上完全随机输入。
将人工生成的密码转换为密钥的正确方法是 运行 通过 KDF(这就是它被称为 "key derivation function" 的原因)。如果您只关心身份验证(验证用户知道正确的密码),那么添加额外的加密步骤就没有任何价值。您可以只使用拉伸键。
扩展密码(KDF 的输出)是唯一应该发送到服务器的东西。然后服务器应使用 SHA-2 对该值再进行一次哈希处理并存储它。这样,呈现给服务器的密钥就与存储在数据库中的密钥不同,即使数据库被盗,也无法用于向服务器进行身份验证。