用 asm.js 写了一个慢哈希的 demo

2015-08-13 14:09:47 +08:00
 zjcqoo

慢哈希就是计算速度很慢的哈希函数,例如 bcrypt,计算一次花费几百毫秒的时间,这样就大幅降低破解的速度。

但这样会给服务器很大的计算压力,容易被拒绝服务。

不过现在浏览器的性能越来越好了,而且支持多线程计算,甚至还出现了 asm.js 这样的高性能方案,所以可以把慢函数的计算放到前端来完成。

注册时,用户可以选择一个合适的时间强度,浏览器在该时间段内,尽可能多的重复计算 Hash 函数,最后将 账号、Salt(前端生成)、Hash、重复次数 提交。

图1

登陆时,先获取指定用户的 Salt 和 次数,然后将 Hash(密码 + Salt) 重复 turn 次,消耗注册时指定的时间,最后提交。

图2

这样就算被拖库,破解成本也大幅增加。相比传统的简单 Hash,要慢上很多个数量级。

而且在前端计算还有另外一个好处:可以增加登录成本。对于每个用户来说,登录时多等一两秒并没多大影响,无非就是输验证码的时间。但对于撞库的人来说,就是很大的瓶颈了。

Demo: http://121.43.101.95:8080/

5132 次点击
所在节点    分享创造
30 条回复
yyfearth
2015-08-14 02:15:46 +08:00
@Numbcoder @iyangyuan

我之前也是这么想的 所以没有去实现 可是https已经颜面扫地了
现在看来 https 只是最低保障 —— 不用https是肯定不行的
但是用https就没问题么?heartbleed 不就可以泄漏用户原密码么
所以前端做预处理 还是有点意义的 可以保护用户的原始密码
至少可以让弱密码看上去也不那么弱 就算是弱密码也得算个半天
rtyurtyu
2015-08-14 09:44:18 +08:00
自欺欺人,没有任何意义的方法,纯粹浪费地球资源
前面已经有人总结的很好了

说个其他方面的副作用:
所有记住密码的功能、扩展、插件等等都会失效
妨碍了用户的正常使用功能
Numbcoder
2015-08-14 10:21:56 +08:00
既然采用了 https,就应该默认他是安全的,就好比你用 bycrpt, rsa,你怎么知道这些就是安全呢?
如果按照你这逻辑扣下去,linux,mysql 都可能存在未知的漏洞和 bug,就都不能用了?这世界上也没有一个软件或系统是绝对安全的。

再说了 heartbleed 是 openSSL 的问题,和 https 有毛关系啊。
Numbcoder
2015-08-14 10:22:13 +08:00
@yyfearth 忘了@你
yyfearth
2015-08-14 11:02:13 +08:00
@Numbcoder 就算可以认为https协议本身是安全的 但是不能说明他的实现都是安全的
heartbleed 就是一个例子 而且openSSL也是适用最广泛的实现 而且之后还出现了很多很多漏洞
足以说明仅仅依靠https传输明文密码已经没有想象中那么安全可靠

而且我是说 “https一定要用” 而不是“有漏洞就不能用”
既然一套系统不够安全可靠 那么可以依赖多套系统叠加增加破解的难度
就算采用了 https 但是也不能默认他是安全的 因为硬件升级和算法的更新
很多https支持的老算法和设置也逐渐变的不再安全 比如 MD5 RC4 SHA1 SSL3 这样的算法或版本
你需要做一些额外的设置和机制 才可以跟上安全的步伐

更况切 对于 “https + 服务端 bcrypt(password + salt)” 就足够 我并没有反对
LZ这个帖子主要是为了解决后端慢哈希函数bcrypt效率低下 可能有DoS的风险
所以把一部分计算量放到前端来实现的想法 这个和用https并不冲突
只是LZ的想法还不够完善 所以我把我之前的想法发出来供LZ和大家讨论
我的想法的核心思想是 必须拥有原始密码才可以通过验证 而且把尽量多的运算量移到前端
后端只需要一部分的计算量就可以达到 原本需要很大计算量的效果
yyfearth
2015-08-14 11:07:53 +08:00
@rtyurtyu 我之前也是这么认为的 但是现在觉得是一个选择 如果对安全的需求比较高的话

对于 “说个其他方面的副作用: 所有记住密码的功能、扩展、插件等等都会失效 妨碍了用户的正常使用功能”
这个问题并不大 目前很多webapp已经都是使用 Ajax 来提交用户信息 而不是直接通过Form来提交
所以不会导致修改Form引起插件、扩展抓到hash后的密码
目前国内有些网站是这样做的 我也觉得不太好

对于ajax提交而不是form提交 一些插件、扩展抓取不到
是这些都是他们自己的问题 因为我用的1password以及Chrome/Safari都没问题 可以抓取
说明其他的插件、扩展也可以做到
rtyurtyu
2015-08-14 11:53:36 +08:00
@yyfearth ff自己的记住密码功能就记不住ajax提交,它只在form提交执行时才能抓取
ajax千变万化的,我觉得这个不能赖ff,应该是网站开发者去想办法适配浏览器

另外你上面的改进想法,其实本质上跟lz的一样
每次随机n次传不一样的hash,这并没有增强安全性,因为抓包的抓到任何一个hash都能当成正确密码来用
而且你这样还得带着n给服务器端
这个只迷惑了自己,而不是别人
NeoAtlantis
2015-08-14 21:20:09 +08:00
在浏览器上搞密码一般是个坏主意,stackoverflow上对此多次警告,理由和楼上各位差不多。不要自己发明轮子,用了https没必要加密,不用https那么js自己就不安全。

我个人觉得有https再加密也是可以的,有时候设计好了可以做到mega网盘那种让服务器也不知道你的内容的安全。但是bcrypt这样的算法只在其特别有效率地运行时才有意义,所以js上来搞有点难。
NeoAtlantis
2015-08-14 21:21:36 +08:00
不要自作聪明设计密码算法!
不要自作聪明设计密码算法!
不要自作聪明设计密码算法!

重说三
notcome
2015-08-17 05:23:24 +08:00
如果中间人攻击的话,似乎怎么整都没有用,所以我之前一个小网战直接 HTTPS 明文密码,到服务器端 bcrypt。不过现在感觉至少也要 hash 一下。

不过那个网站是真的超小超 ad hoc。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/212939

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX