用 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/

4925 次点击
所在节点    分享创造
30 条回复
Numbcoder
2015-08-13 14:26:43 +08:00
这样的话,所有人的 salt 都被暴露了把
zjcqoo
2015-08-13 14:29:38 +08:00
这个 salt 给前端计算用的。后端储存的时候可以和传统一样,用隐藏的算法和 salt。
feiyuanqiu
2015-08-13 14:30:24 +08:00
有个疑问,我看登陆的时候你是直接在前端计算出hash后的密码,这个密码和数据库保存的是一样的
那么如果这个请求被嗅探了密码不就泄露了吗
w88975
2015-08-13 14:30:59 +08:00
慢hash是什么玩意?
Numbcoder
2015-08-13 14:32:16 +08:00
@feiyuanqiu 你直接用户名密码登录难道就不会被嗅探?
feiyuanqiu
2015-08-13 14:32:39 +08:00
@feiyuanqiu 你现在的方案其实就是明文保存密码吧
tabris17
2015-08-13 14:33:02 +08:00
你这最多防网络嗅探而已,不防爆库
Numbcoder
2015-08-13 14:33:57 +08:00
@zjcqoo 其实服务端直接用 bcrypt 并不会慢多少,Rails 早就默认用 bcrypt 了
feiyuanqiu
2015-08-13 14:34:42 +08:00
@Numbcoder

关键是他现在的方案其实就是明文保存
这是登陆请求: http://121.43.101.95:8080/ajax_login?user=123&pwd=73590a3516e926c0e6677943ac2abcd3

这是后台保存的密码:
用户名 MD5(密码 + Salt) * N Salt N (百万) 最后登录时间 最后登录地址 登录成功 登录失败
123 73590a3516e926c0e6677943ac2abcd3 ncnxirug 14 2015-08-13 14:27:31 182.150.24.209 5 0
zjcqoo
2015-08-13 14:40:12 +08:00
@feiyuanqiu 拖库的话,直接提交 Hash 是可以登上其他人的账号的。这个是减慢破解某个账号的原密码。
Numbcoder
2015-08-13 14:41:44 +08:00
@feiyuanqiu 不是明文的
password --> bcrypt + salt --> md5 + salt


但实际上 bcrypt 这一步根本就没用。如果被暴库,只需要破解 md5 这一步得到 bcrypt 的 hash,然而有了这个 hash 就可以直接登录了。。。
feiyuanqiu
2015-08-13 14:45:37 +08:00
@zjcqoo 在这个方案里,原密码其实变成了在用户浏览器哈希后的那个密码,因为传给服务器的就是这个,用户最开始设置的是什么已经无关紧要了。而这个密码现在是以明文保存的,只要脱了库就全完了,连破解都不需要
而如果要在服务器再进行一次加盐哈希的话,那么在前端的哈希就完全没有意义了
zjcqoo
2015-08-13 14:54:34 +08:00
@feiyuanqiu 但还是难破解原密码。小网站的账号被控制就算了,但原密码被破解,就可以拿去猜其他网站同密码的账号了。
yyfearth
2015-08-13 15:04:51 +08:00
@zjcqoo @Numbcoder @feiyuanqiu

其实这个方案我很久以前就考虑过
LZ的方案还不够完善 导致前端hash变得几乎没有意义

不过前端hash还是有办法弄得更加安全的
我之前想出来的办法就是多次分开加密

注册时候
password --> browser: bcrypt + client salt (2000x) --> server:bcrypt + client salt + server salt (100x) -> db

验证的时候
password --> browser: bcrypt + client salt (random 1k+ times) --> server: bcrypt + client salt (2000-client random times) --> server:bcrypt + client salt + server salt (100x) == db

这样就避免了“前端的哈希就完全没有意义了”的问题
然后 由于用同样算法 只是循环次数不同
分一大部分浏览器做 另一小部分服务器做 只要总数一定 结果就应该一样
然后再换一个算法另外一个salt(可以是固定的)保存到数据库 来避免直接脱库的问题
在注册的时候 浏览器做了最大次数的加密
在验证的时候 由于浏览器是随机选择次数 所以可以做到每次结果不一样 避免了和注册时候传输同样的密文
feiyuanqiu
2015-08-13 15:24:42 +08:00
@yyfearth 你这个思路不错呀,我去试试

我记得腾讯微博的登陆也是在浏览器进行了处理再传送的,但是我一直还没有去看它是怎么处理的
Numbcoder
2015-08-13 15:40:37 +08:00
@yyfearth 实在不明白为什么要搞得这么复杂

https + 服务端 bcrypt(password + salt) 就能搞定的事需要这么麻烦吗?
bumz
2015-08-13 16:48:05 +08:00
其實,並沒有什麼卵用。對於使用重複密碼的人來說,會出現木桶效應;對不使用重複密碼的人來說,自然也是沒用的。
RIcter
2015-08-13 16:59:00 +08:00
lz 现在跳阿里了吗?是做前端还是做安全的_(:3」∠)_
zjcqoo
2015-08-13 17:16:28 +08:00
@RIcter 前端安全:)
iyangyuan
2015-08-13 19:18:37 +08:00
在浏览器端做这些只是自欺欺人而已,让https情何以堪

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

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

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

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

© 2021 V2EX