localstorage本身不加密,所有前端加密都是手动实现;真要防泄露应优先避免存储敏感数据,而非加解密——因密钥管理难、易被hook、兼容性差,且基础防护(https、csp、键名混淆)不到位时加密无效。

localStorage 本身不加密,所有“加密存储”都是前端手动加解密——这不是 HTML5 功能,而是你写在 JS 里的逻辑。真要防敏感数据泄露,优先砍掉存 localStorage 的需求,而不是给它套加密外壳。
为什么 crypto.subtle.encrypt + localStorage 还是不安全
Web Crypto API(比如 crypto.subtle.encrypt)确实能加密数据,但关键问题不在算法,而在密钥生命周期:
- 密钥若由用户密码派生(如 PBKDF2),每次解密都需用户输入密码——这适合密码管理器,但不适合自动登录、记住偏好等常规场景;
- 若密钥硬编码在 JS 文件里(比如
const KEY = 'abc123...'),攻击者打开 DevTools → Sources → 找到文件,3 秒内拿到密钥; - 若密钥从后端下发(如登录后返回一个
local_key),那这个 key 本身就得走 HTTPS + 签名校验 + 一次性使用,复杂度远超直接用接口传数据; - 即使加密成功,攻击者仍可 hook
crypto.subtle.decrypt函数,在内存中截获解密后的明文(Chrome DevTools → Console →eval('window.crypto.subtle.decrypt = new Proxy(...)')。
CryptoJS.AES.encrypt 存 localStorage 的实际效果
这是兼容性最好的“快速加密”方案,但只适合低敏字段(如 UI 折叠状态、浅层 token 缓存),别碰手机号、身份证、支付信息:
- 它默认用 AES-CBC 模式,无认证标签(no AEAD),无法检测密文是否被篡改;
- 密钥若写死(如
CryptoJS.enc.Utf8.parse('my-secret-key')),和明文存没区别; - 必须配合
JSON.stringify()/JSON.parse()处理对象,否则解密后得到的是乱码字符串; - 示例中常见错误:
localStorage.setItem('data', CryptoJS.AES.encrypt(obj, key))—— 错!CryptoJS.AES.encrypt()返回的是 CipherParams 对象,不是字符串,必须调用.toString(); - IE 或 Safari 15.6 以下不支持 Web Crypto,CryptoJS 是唯一选择,但记得压缩后体积约 30KB,影响首屏。
localStorage.setItem 前必须做的三件事
哪怕你决定加密,也得先确保基础防护到位,否则加密形同虚设:
- 确认页面强制走 HTTPS:检查地址栏锁图标,且所有资源(
script、iframe、fetch)都用https://,否则中间人可替换你的加密 JS; - 设置严格 CSP:至少禁用
unsafe-inline和unsafe-eval,防止 XSS 注入后直接读取 localStorage 或重写加密函数; - 敏感键名避免暴露语义:别用
localStorage.setItem('user_id_card', ...),改用'uic_7f2a'这类无意义前缀,配合定期扫描上报(如监听setItem并正则匹配/idcard|bank|pwd/i)。
真正该加密的不是 localStorage 里的值,而是你为什么需要把它放进去——多数时候,删掉那一行 localStorage.setItem,换成 fetch('/api/user/profile', { credentials: 'include' }),才是最短路径的安全。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











