security - 用密码与哈希加密密码
问题描述
我正在为我们的一个内部工具构建身份验证服务,在查看了各种文章之后,我可以将它们总结为
- 不要使用加密,因为如果发生泄露,私钥可能会危及一切。
- 使用带盐的散列来存储散列并简单地比较散列。这样,即使哈希被泄露,也无法获得实际密码。
我知道任何可能导致明文密码的东西都是不好的,但我只是想知道为什么没有人使用密码来加密密码,比如说,AES256
?我的意思是,由于它是对称加密,它没有任何私钥。因此,即使发生泄露,也无法取回实际密码。加盐密码并用密码本身加密有什么问题?
解决方案
加盐密码并用密码本身加密有什么问题?
这是一个非常快速的操作,可以非常快速地测试(即“破解”)密码。使用 SHA-2 之类的算法进行简单散列也是如此。处理密码的正确方法是加盐和拉伸它们(而不是简单地散列它们)。“拉伸”意味着通过称为 KDF(密钥派生函数)的时间密集型算法(例如 PBKDF2 或 scrypt)运行它们。
同样重要的是,人工生成的密码无论如何都不能直接用于使用 AES 进行加密。AES 需要一个精确大小(16、24 或 32 字节)的密钥,并且为了确保密钥在整个密钥空间中完全随机的安全性。人工生成的密码很少是正确的长度,并且在整个密钥空间中永远不会随机(既因为人类是较差的随机值生成器,又因为 32 个可键入字符只是所有可能的 32 字节密钥的一小部分;要正确键入这样的密钥, “密码”需要将近 40 个字符长,并且使用通用键盘上的所有大写/小写字母、数字和符号完全随机输入)。
将人工生成的密码转换为密钥的正确方法是通过 KDF 运行它(这就是为什么它被称为“密钥派生函数”)。如果您只关心身份验证(验证用户是否知道正确的密码),那么添加额外的加密步骤没有任何价值。您可以只使用拉伸键。
扩展密码(KDF 的输出)是唯一应该发送到服务器的内容。然后,服务器应该使用 SHA-2 再对该值进行一次散列并存储它。这样,呈现给服务器的密钥与存储在数据库中的密钥不同,即使数据库被盗,也无法用于向服务器进行身份验证。
推荐阅读
- php - 如何使不同形式的按钮彼此相邻?
- python - JavaScript 适用于 chrome 控制台,但不适用于 firefox 或 selenium 代码
- angular - 时刻js如何检查结束时间是否在开始时间之后
- ios - 仅对参数属性可用的函数
- javascript - How to download a file with nodeJS
- java - Spring Boot 作为战争与 jar
- windows - 在不同的 PC 上运行相同的 power-shell 命令时出错
- docusignapi - 使用 DocuSign API 自动签名文档
- regex - GSTIN Validation through condition not working in Perl
- mysql - Print name of all activities with neither maximum nor minimum number of participants