你还在纠结前端要不要提交明文口令?这个十年前就有结论的问题每隔一段时间都会有人讨论。结论是不管什么环境,前端提交 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)
而网页登陆的用户名,就是 hash 函数的密码(也叫 salt)这样做有什么好处呢,那就是针对用户名 A 建立的彩虹表,无法用于用户名 B/C/D 。不同用户名只能单独计算,这就增加了密码防撞的安全性。
前端传可解密的密文,更能适应技术升级,未来你 db 用的 hash 算法被认为不安全了,也可以在用户重新登录时更换新的 hash 算法。而前端传 hash ,未来前端技术升级,你要把 hash 当密码,要么同时传可解密密码和 hash ,反正原 hash 是甩不掉了。