别再纠结前端要不要提交明文口令,浏览器已经内置非常好的方案

39 天前
 iqoo

这个十年前就有结论的问题每隔一段时间都会有人讨论。结论是不管什么环境,前端提交 hash 后的口令总是好的,防的不是中途的嗅探者,而是脱库后的破解者。前端 hash 越耗时,脱库后跑字典越慢。

至于前端 hash 也不用自己捣鼓 js/wasm 这些,主流浏览器早已内置 PBKDF2 算法,较新的 CPU 都有相应的硬件加速,比自己实现可以快很多倍。

演示:

const username = new TextEncoder().encode('alice')
const password = new TextEncoder().encode('hello1234')

// 重复 1000 万次 SHA256
const pbkdfOpts = {
  name: 'PBKDF2',
  hash: 'SHA-256',
  salt: username,
  iterations: 1e7,
}

async function pbkdf2(pwd, opts, bits) {
  const baseKey = await crypto.subtle.importKey('raw', pwd, 'PBKDF2', false, ['deriveBits'])
  const buf = await crypto.subtle.deriveBits(opts, baseKey, bits)
  return new Uint8Array(buf)
}

const dk = await pbkdf2(password, pbkdfOpts, 256)

// 注册/登录提交 dk 即可,无需提交 password
console.log(dk)

9520 次点击
所在节点    程序员
93 条回复
yjhatfdu2
39 天前
我感觉很多人既不懂加密、又不懂安全、又没有逻辑,楼主还是很懂的
gavin810
39 天前
我在做一个比较小的项目的时候,鉴权设计主要是听甲方的——前后端都得 hash 。
但我个人觉得觉得前端大多数情况下都没有必要做 hash ,https 和后端的加密就已经足够了。哲学上有个概念,奥卡姆剃刀原理,如无必要,勿增实体。代码设计上也有一种思想,worse is better ,我感觉有点不谋而合。

绝对的安全是很难保证的。

毕竟自己的网站设置再复杂的 hash 函数,迭代的次数再多,加再多的盐,也很难防止用户自己泄露或者其他网站的密码库泄露。不是所有人都会对每个网站设不同的用户名密码,也不是所有网站的安全性都很高,或者有些无良网站干脆就存明文。
在这种情况下,前端加 hash 唯一能提供的,就是开发人员给自己的一些合理的技术安慰,在泄密时保护了自己网站的密码,虽然这总归是好的。

所以加或者不加,很大程度上取决于你的需求。

参考《加盐 hash 保存密码的正确方式.md
https://github.com/su18/wooyun-drops/blob/b2a5416/papers/%E5%8A%A0%E7%9B%90hash%E4%BF%9D%E5%AD%98%E5%AF%86%E7%A0%81%E7%9A%84%E6%AD%A3%E7%A1%AE%E6%96%B9%E5%BC%8F.md
fly2never
39 天前
如果有跨平台的 c++库(比如 openssl)支持还行, 很多 api 需要 多端调用, 用 c++开发复用才能做到最大范围覆盖
forgottencoast
39 天前
@danhahaha
现在只要稍微有点良心的网站都不会允许纯数字的密码,别说 123456 了。
BeautifulSoap
39 天前
看了这么多觉得前段 hash 是极有必要安全非常非常多的人的言论,我有一种感觉,是不是觉得前端 hash 有必要的基本都是前端工程师

要不然怎么会出现如此奇怪的在完全不相信后端的同时,又同时完全相信同一个公司做出的网页前端?
hesetiema
39 天前
用 wasm 代替 js 做 hash 或者加密,是不是更好呢...
restkhz
39 天前
黑客看到普通登录框,没验证码:先上 burp 爆破
黑客看到楼主登录框,没验证码:咦?这个 burp 好像跑不了。(看源码) md 这个人怎么实现登录都搞这么 xxx 复杂!不搞了! burp 关闭!

黑客看到 md5: 查查 cmd5 ,没有?字典跑跑。还没有?算了。(他甚至没注意你有没有加盐)
黑客看到 bcrypt: 字典跑跑(五分钟以后)admin123

楼主你的安全不是因为你 hash 方法牛逼防止拖库后被破解,
而是实现方法足够复杂直接让黑客从开始就放弃。
退敌于千里,治病于腠理。实在是高!

底下讨论:
有些人正在重新发明 TLS ,
有些人说一些有的没的,
只有 Chad0000 在努力证明楼主这样做不值得。

实话说,我也觉得没必要。但是想想也不是不行,理由如上。
hesetiema
39 天前
Chad0000
38 天前
@restkhz #87
我理解 OP 想避免被脱库,但增加脱库难度有很多方案,OP 偏偏选了一种“御敌 999 ,自损 300”的做法。我上面的说法就是在说这种自损是否值得。就没更好更优雅的方案了么?当然有啊,其中之一就是脱库者都不知道加密方式(未拿到软件系统),盐也不在 DB 中(算出来的),每个用户加密会根据用户本身信息而变(比如用户密码版本号),那对脱库的也是一种打击。
xuanbg
38 天前
随便加个盐或 2 次 md5 彩虹表就废了,密码传输的安全性早有定论,不明白这种问题为何还成了月经贴
ZhiyuanLin
38 天前
2024 年了,可以用 Passkey 。
别瞎折腾密码了。
baobao1270
38 天前
1. crypto.subtle 这个 API 其实出现很久了,但是主流的厂商并没有使用。我也不知道为啥,反正我是用了。具体的兼容性可以看 https://caniuse.com/cryptography

2. 这个 API 既有哈希算法,又有非对称/对称加密算法。个人其实还是推荐前端做 RSA 加密而不是直接把哈希给后端。这么做有两个原因:一是盐始终应该在服务器端随机生成且客户端不可知(这就排除了客户端生成或者使用用户名做盐的做法);二是处于业务的需要,服务器是有必要知道用户的明文密码的,场景包括:
a. 在后端也应该过一遍密码强度检查,不可以直接信任用户的输入
b. 对常见易猜或已知泄露的密码进行检测并提示用户
c. 对密码进行敏感检查(我也不知道为啥有这个需求,但是新浪一直有这个机制)
d. 过滤密码中的不可显示字符和非 ASCII 字符(我是认为应该禁止用户使用非 ASCII 字符作为密码的——虽然会牺牲一定安全性,但是从业务的角度考虑,如果用户在一个设备上不小心输入了什么奇怪的字符、在另一个设备上输不进去了,搞不好会怪你——说到底还是业务和安全的 trade-off )

3. 哈希算法的话,也是 argon2id 优于 PBKDF2 ,只是前者没有 FIPS 认证,对于需要安全认证的业务还是只能用 PBKDF2 。
mark2025
38 天前
@gamexg 这是入库的对于明文口令摘要的密文口令,如果被拖库或者其它方式拿到这个值,的确可以直接登录的。但这儿摘要的目的是避免通过这个密文解算出用户的明文口令,然后拿到其它网站去入侵。
而实际用户在登录的时候是输入明文口令算出密文口令,然后拿服务器给出的随机盐再做一次散列。服务器拿到后用数据库保存的密文口令通过相同算法计算出的值去比较。

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

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

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

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

© 2021 V2EX