JavaScript不能安全加密密码,因前端代码完全暴露,任何加密逻辑均可被反编译或绕过;安全核心必须依赖后端用bcrypt或Argon2等强算法进行不可逆哈希。
JavaScript 本身不能安全地“加密”密码,真正安全的做法是在前端做哈希加盐处理(仅作预校验或辅助),但核心必须依赖后端用强算法(如 bcrypt、Argon2)完成不可逆哈希。浏览器环境无法保证密钥或算法逻辑不被窥探,直接在前端“加密”容易误导开发者,反而降低安全性。
前端代码完全暴露在用户浏览器中,任何所谓“加密”逻辑(比如用 CryptoJS 做 AES)都可被轻易反编译、调试绕过。攻击者能直接获取原始密码,或替换你的加密函数为恒等函数。更危险的是,若你把密钥硬编码在 JS 里,等于把锁的钥匙贴在门上。
HA-1、SHA-256 等哈希都不是密码哈希——它们太快,易被暴力破解或查表攻击可在提交前用 SubtleCrypto.digest() 对密码+随机盐(由后端生成并返回)做一次 SHA-256 哈希,作为传输摘要(非存储用)。这能防止明文密码意外暴露在日志或中间代理中,但绝不替代后端密码哈希。
async function hashPassword(password, salt) {
const encoder = new TextEncoder();
const data = encoder.encode(password + salt);
const hash = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
⚠️ 注意:盐不能写死,也不能由前端生成后直接发给后端——否则攻击者可重放该盐发起离线爆破。真实场景中,盐应由后端在登录请求时随 challenge 一并下发,且单次有效。
所有密码必须在服务端用专用密码哈希函数处理:
例如 Node.js 中使用 bcrypt:
// 注册时 const saltRounds = 12; const hash = await bcrypt.hash(password, saltRounds); // 登录时 const isValid = await bcrypt.compare(inputPassword, storedHash);
type="password" 并禁用 autocomplete(autocomplete="new-password")