当源代码可用时,如何正确保护密码
How do I properly protect a password when the source code is available?
我正在构建一个web应用程序,该应用程序具有用户登录功能,我希望使其尽可能安全。当创建一个新用户时,我使用这个javascript函数来散列用户的信息,并最终将输出存储在mySQL数据库中:
function hash(user) {
var part1 = mix(user.username, user.password);
var part2 = mix(user.random_value + salt, user.password);
return mix(part1, part2);
function mix(part1, part2) {
var hash = sha3_256(part1 + part2);
var rehash = 10000;
while(rehash--) {
hash = sha3_256(hash + salt + rehash);
}
return hash;
}
}
数据库包含用户名、随机值和hash函数的输出,而salt变量是在函数外部声明的随机字符串,永远不会更改。
根据我之前阅读的一些关于密码安全的帖子,这是一种相当安全的做事方式(尽管我很感激任何建议),但我担心的是:
如果我假设有人可以访问数据库,获得为某个用户存储的所有信息,并且他可以准确地看到哈希函数的操作方式(因为这些代码在浏览器和GitHub上都可见)。难道这个恶意的人就不能通过我的函数运行所有可能的8个字符(最小密码长度)的组合,看看密码的值能创建正确的哈希吗?
这肯定需要一些时间,但最终浏览所有可能性并因此访问该帐户并非不可能。
有什么方法可以防止这种攻击吗?
谢谢!
附带说明:我假设您在服务器端(nodejs?)执行此操作。您的实现是非标准的,并且您的术语是混合的(正常的术语将"salt"作为一个值,每次都会更改,而"pepper"是一个固定的服务器端字符串),但它确实有主要的概念。不过,我建议您使用标准的"密码哈希"算法,如scrypt或bcrypt。
关于你的问题"这个恶意的人不能通过我的函数运行所有可能的8个字符(最小密码长度)的组合,看看密码的值能创建正确的哈希吗?",答案是肯定的,但他需要很长时间才能做到这一点。这就是rehash
变量的全部目的:降低用户的速度。请参阅:我们的密码哈希没有衣服了解更多细节。
您的威胁模型是"攻击者可以完全读取数据库内容",是吗?
解决方案是:
- 不要让这种事发生
- 将web服务器与数据库服务器分离,并使用Peppering
这涉及到将机密存储在web服务器上(从不存储在数据库服务器上)。首先使用此选项HMAC密码。然后将其散列存储。
如果数据库服务器遭到破坏,密码就无法轻易破解。即使攻击者可以进行SQL注入,但无法获得web服务器信息,这也会起作用
注:
- 不要将SHA{anything}用于密码哈希。仅使用bcrypt、scrypt或PBKDF2
- 不要使用自己的安全系统。使用现有框架
- 您的系统应该是安全的,即使它是开源的。看见https://en.wikipedia.org/wiki/Kerckhoffs%27s_principle
- 在你的网络上运行HIDS,在你的数据库服务器上运行NIDS,这样你就可以(希望)检测到漏洞并通知你的用户,这样他们就可以在其他网站上更改密码
如果您使用的是一个足够好的哈希算法,那也没关系。这是因为(强调矿)
密码散列函数是一种数学算法,它将任意大小的数据映射到固定大小的比特串(散列函数),该比特串也被设计为单向函数,也就是说,不可行反转的函数。
加密哈希被设计为开源的,在明文密码存储中使用它们的目的是,如果数据被破坏,根密码是不可逆的。此上的Wiki
现在,如果你自己滚动了,或者试图阻止别人知道你在使用弱哈希算法,你就有麻烦了。
此外,您的盐/胡椒应该只存在于应用程序的实例化中。您当然可以将其加载到github,但我建议您在实际应用程序中更改该配置。
为了解决您对每个8个字符的密码都要运行的问题,这只是一个彩虹表问题。这就是为什么使用hunter2是一个错误的密码。你的盐/胡椒有助于缓解这种情况,但总的来说,猜测是不可行的。这很好地说明了头脑中的时机。
难道这个恶意的人就不能通过我的函数运行所有可能的8个字符(最小密码长度)的组合,看看密码的值能创建正确的哈希吗?
当然一个好的密码哈希的目标是减缓对手生成每个哈希所需的时间,尤其是因为在传统CPU上可能"慢"的东西在GPU(或许多;想想加密采矿场)或ASIC上可能很快。
这就是为什么设计了bcrypt、scrypt和Argon等密码哈希算法。(问题中显示的函数更类似于PBKDF2,它不是内存硬。)
因此,忽略仅依赖于代码外存储/管理的附加秘密的尝试(例如PKI私钥或"胡椒"),两个通用选项是:
-
使对手的哈希函数变慢。
请参阅上面提到的密码散列函数之一,它在GPU/ASIC上提供不同级别的硬度;
-
帮助用户选择具有更多密钥熵的更长的密码短语。这有一个隐含的目标,即在常见的密码字典中找不到这样的"密码"。
除了用户教育(例如清晰的消息传递)帮助是要求"密码"至少为12/14个字符,并且取消一些传统限制。像输入空间增加了,即使是快速暴力方法变得不那么吸引人。参见强制性链接
由于显示的原始自旋转函数与PBKDF2相比没有固有优势,而且缺点是不是一个经过仔细检查的算法,因此我建议使用具有适当盐/输出大小和迭代次数的PBKDF2
还可以通过一个KDF(包括一轮的PBKF2)来简单地支持一个"pepper",以提供实际的迭代哈希。
- React重新渲染但未显示正确的组件
- 我的jQuery插件参数没有正确启动,遇到了问题
- Jquery菜单操作不稳定,定位不正确,存在一般错误
- Amazon S3 REST API大小不正确
- document.open/document.write没有正确地清除chrome中的文档——这是chrome的错误吗
- Javascript Reg Exp不正确匹配
- Javascript计数器变量未显示正确的值
- MeteorJS:在带有回调的vzaar api上正确使用wrapAsync
- JS表单提交"无法使用Chrome数据保护程序加载此页面.尝试重新加载页面.调试信息:POST CISmtuK
- Meteor方法在客户端返回null,在客户端运行的相同方法返回正确的值
- 将日期时间作为 JSON 发送将无法在我的视图中正确显示
- DIV并排,位置不正确
- 从查询字符串参数推断出正确的数据类型
- 我能得到正确的格式吗
- 仅在IE中,javascript中的时区名称不正确
- 如何正确使用jsPDF
- 正确传输和保护用户'web应用程序的密码
- 当源代码可用时,如何正确保护密码
- 如何正确保护表单平面文件数据库
- 如何在AngularJS中正确保护密码