慢哈希就是计算速度很慢的哈希函数,例如 bcrypt,计算一次花费几百毫秒的时间,这样就大幅降低破解的速度。
但这样会给服务器很大的计算压力,容易被拒绝服务。
不过现在浏览器的性能越来越好了,而且支持多线程计算,甚至还出现了 asm.js 这样的高性能方案,所以可以把慢函数的计算放到前端来完成。
注册时,用户可以选择一个合适的时间强度,浏览器在该时间段内,尽可能多的重复计算 Hash 函数,最后将 账号、Salt(前端生成)、Hash、重复次数 提交。
登陆时,先获取指定用户的 Salt 和 次数,然后将 Hash(密码 + Salt) 重复 turn 次,消耗注册时指定的时间,最后提交。
这样就算被拖库,破解成本也大幅增加。相比传统的简单 Hash,要慢上很多个数量级。
而且在前端计算还有另外一个好处:可以增加登录成本。对于每个用户来说,登录时多等一两秒并没多大影响,无非就是输验证码的时间。但对于撞库的人来说,就是很大的瓶颈了。
1
Numbcoder 2015-08-13 14:26:43 +08:00
这样的话,所有人的 salt 都被暴露了把
|
2
zjcqoo OP 这个 salt 给前端计算用的。后端储存的时候可以和传统一样,用隐藏的算法和 salt。
|
3
feiyuanqiu 2015-08-13 14:30:24 +08:00
有个疑问,我看登陆的时候你是直接在前端计算出hash后的密码,这个密码和数据库保存的是一样的
那么如果这个请求被嗅探了密码不就泄露了吗 |
4
w88975 2015-08-13 14:30:59 +08:00
慢hash是什么玩意?
|
5
Numbcoder 2015-08-13 14:32:16 +08:00
@feiyuanqiu 你直接用户名密码登录难道就不会被嗅探?
|
6
feiyuanqiu 2015-08-13 14:32:39 +08:00
@feiyuanqiu 你现在的方案其实就是明文保存密码吧
|
7
tabris17 2015-08-13 14:33:02 +08:00
你这最多防网络嗅探而已,不防爆库
|
9
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 |
10
zjcqoo OP @feiyuanqiu 拖库的话,直接提交 Hash 是可以登上其他人的账号的。这个是减慢破解某个账号的原密码。
|
11
Numbcoder 2015-08-13 14:41:44 +08:00
@feiyuanqiu 不是明文的
password --> bcrypt + salt --> md5 + salt 但实际上 bcrypt 这一步根本就没用。如果被暴库,只需要破解 md5 这一步得到 bcrypt 的 hash,然而有了这个 hash 就可以直接登录了。。。 |
12
feiyuanqiu 2015-08-13 14:45:37 +08:00
@zjcqoo 在这个方案里,原密码其实变成了在用户浏览器哈希后的那个密码,因为传给服务器的就是这个,用户最开始设置的是什么已经无关紧要了。而这个密码现在是以明文保存的,只要脱了库就全完了,连破解都不需要
而如果要在服务器再进行一次加盐哈希的话,那么在前端的哈希就完全没有意义了 |
13
zjcqoo OP @feiyuanqiu 但还是难破解原密码。小网站的账号被控制就算了,但原密码被破解,就可以拿去猜其他网站同密码的账号了。
|
14
yyfearth 2015-08-13 15:04:51 +08:00 1
@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(可以是固定的)保存到数据库 来避免直接脱库的问题 在注册的时候 浏览器做了最大次数的加密 在验证的时候 由于浏览器是随机选择次数 所以可以做到每次结果不一样 避免了和注册时候传输同样的密文 |
15
feiyuanqiu 2015-08-13 15:24:42 +08:00
|
16
Numbcoder 2015-08-13 15:40:37 +08:00
|
17
bumz 2015-08-13 16:48:05 +08:00
其實,並沒有什麼卵用。對於使用重複密碼的人來說,會出現木桶效應;對不使用重複密碼的人來說,自然也是沒用的。
|
18
RIcter 2015-08-13 16:59:00 +08:00
lz 现在跳阿里了吗?是做前端还是做安全的_(:3」∠)_
|
20
iyangyuan 2015-08-13 19:18:37 +08:00 via iPhone
在浏览器端做这些只是自欺欺人而已,让https情何以堪
|
21
yyfearth 2015-08-14 02:15:46 +08:00
|
22
rtyurtyu 2015-08-14 09:44:18 +08:00
自欺欺人,没有任何意义的方法,纯粹浪费地球资源
前面已经有人总结的很好了 说个其他方面的副作用: 所有记住密码的功能、扩展、插件等等都会失效 妨碍了用户的正常使用功能 |
23
Numbcoder 2015-08-14 10:21:56 +08:00
既然采用了 https,就应该默认他是安全的,就好比你用 bycrpt, rsa,你怎么知道这些就是安全呢?
如果按照你这逻辑扣下去,linux,mysql 都可能存在未知的漏洞和 bug,就都不能用了?这世界上也没有一个软件或系统是绝对安全的。 再说了 heartbleed 是 openSSL 的问题,和 https 有毛关系啊。 |
25
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和大家讨论 我的想法的核心思想是 必须拥有原始密码才可以通过验证 而且把尽量多的运算量移到前端 后端只需要一部分的计算量就可以达到 原本需要很大计算量的效果 |
26
yyfearth 2015-08-14 11:07:53 +08:00
@rtyurtyu 我之前也是这么认为的 但是现在觉得是一个选择 如果对安全的需求比较高的话
对于 “说个其他方面的副作用: 所有记住密码的功能、扩展、插件等等都会失效 妨碍了用户的正常使用功能” 这个问题并不大 目前很多webapp已经都是使用 Ajax 来提交用户信息 而不是直接通过Form来提交 所以不会导致修改Form引起插件、扩展抓到hash后的密码 目前国内有些网站是这样做的 我也觉得不太好 对于ajax提交而不是form提交 一些插件、扩展抓取不到 是这些都是他们自己的问题 因为我用的1password以及Chrome/Safari都没问题 可以抓取 说明其他的插件、扩展也可以做到 |
27
rtyurtyu 2015-08-14 11:53:36 +08:00
@yyfearth ff自己的记住密码功能就记不住ajax提交,它只在form提交执行时才能抓取
ajax千变万化的,我觉得这个不能赖ff,应该是网站开发者去想办法适配浏览器 另外你上面的改进想法,其实本质上跟lz的一样 每次随机n次传不一样的hash,这并没有增强安全性,因为抓包的抓到任何一个hash都能当成正确密码来用 而且你这样还得带着n给服务器端 这个只迷惑了自己,而不是别人 |
28
NeoAtlantis 2015-08-14 21:20:09 +08:00 via Android
在浏览器上搞密码一般是个坏主意,stackoverflow上对此多次警告,理由和楼上各位差不多。不要自己发明轮子,用了https没必要加密,不用https那么js自己就不安全。
我个人觉得有https再加密也是可以的,有时候设计好了可以做到mega网盘那种让服务器也不知道你的内容的安全。但是bcrypt这样的算法只在其特别有效率地运行时才有意义,所以js上来搞有点难。 |
29
NeoAtlantis 2015-08-14 21:21:36 +08:00 via Android
不要自作聪明设计密码算法!
不要自作聪明设计密码算法! 不要自作聪明设计密码算法! 重说三 |
30
notcome 2015-08-17 05:23:24 +08:00 via iPhone
如果中间人攻击的话,似乎怎么整都没有用,所以我之前一个小网战直接 HTTPS 明文密码,到服务器端 bcrypt。不过现在感觉至少也要 hash 一下。
不过那个网站是真的超小超 ad hoc。 |