客户端提交表单前对密码做SHA-512哈希,未生效直接提交原密码如何解决
问题原因
crypto.subtle.digest是异步API,返回Promise对象,原有逻辑不会等待哈希计算完成就会触发表单默认提交行为,因此上传的仍是原始密码。
修复方案
放开注释的event.preventDefault()先阻止默认提交,等哈希计算完成后手动调用表单提交方法即可,手动提交不会重复触发onsubmit事件,不会出现循环提交问题。
修正后的完整代码
<html> <head> <title>登录</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <h1></h1> <form method="post" action="login" id="loginForm"> <input type="text" name="user_id"> <input type="password" name="password" id="pass"> <button id="but1" type="submit">提交</button> </form> <script> const loginForm = document.getElementById('loginForm'); const passInput = document.getElementById('pass'); const submitBtn = document.getElementById('but1'); loginForm.addEventListener('submit', async (event) => { event.preventDefault(); // 提交前禁用按钮防止重复点击 submitBtn.disabled = true; submitBtn.innerText = '处理中...'; try { // 计算哈希 const hashVal = await sha512(passInput.value); passInput.value = hashVal; document.querySelector("h1").innerHTML = hashVal; // 手动提交表单 loginForm.submit(); } catch (err) { alert('密码处理失败,请刷新页面重试'); submitBtn.disabled = false; submitBtn.innerText = '提交'; } }) function sha512(str) { return crypto.subtle.digest("SHA-512", new TextEncoder("utf-8").encode(str)).then(buf => { return Array.prototype.map.call(new Uint8Array(buf), x=> (('00'+x.toString(16)).slice(-2))).join(''); }); } </script> </body> </html>
更优实现建议
- 安全注意:客户端哈希只能避免明文密码在传输过程中被直接窃听,无法替代服务端加盐哈希逻辑。攻击者拿到客户端生成的哈希值可直接发起重放攻击登录,因此服务端必须对收到的密码值再做一次加盐哈希后再进行校验/存储。
- 如果你不需要表单跳转提交,可以改用Fetch API异步提交表单,无需刷新页面即可处理登录结果,用户体验更好。
crypto.subtleAPI仅支持HTTPS和localhost环境,公网HTTP环境下该API会被浏览器禁用,此时需要替换为第三方哈希算法库实现计算。- 如果你的站点已经部署HTTPS,传输层已经有加密保障,客户端哈希的收益很低,优先保证服务端加盐哈希的正确性即可。
内容的提问来源于stack exchange,提问作者tinku kalluri
相关产品推荐
相关产品推荐

