客户端加密的安全边界
一句话:framework 的客户端加密仅作 obfuscation,防止 cookie / localStorage 内容被旁人偶然看见。不构成真正的安全屏障。 真正的安全依赖 HTTPS + 后端鉴权。
加密在哪里被使用
framework 在 4 个地方做客户端加密(全部 AES-CBC + 随机 IV):
| 地点 | 入口 | 加密内容 |
|---|---|---|
| Cookie | useCookie('xxx')(utils/cookie.ts) | tokenInfo / deviceId / channel_code / share_code 等 |
| localStorage | useLocal('xxx', init) | AccountInfo(账号 / 密码 / "记住我"勾选)等业务自定义 |
| sessionStorage | useSession('xxx', init) | 业务自定义 |
| API 请求 | request 插件自动加密 POST body | 通过 aes-dynamic(HmacSHA256 按 requestId 派生每请求密钥) |
为什么"不是真正的安全"
加密密钥来自 runtimeConfig.public.cacheAesKey / runtimeConfig.public.apiKey:
// nuxt.config.ts —— 项目常量直接写实值(随代码走,运行时同名 NUXT_PUBLIC_* env 仍可覆盖)
runtimeConfig: {
public: {
cacheAesKey: 'your-16-byte-key', // 16 / 24 / 32 字节
apiKey: 'your-backend-key', // 与后端约定的请求加密密钥
}
}
任何在 runtimeConfig.public.* 下的字段都会被 Nuxt 序列化进 __NUXT__.config.public 注入到客户端 HTML,任何用户打开 DevTools 一行 JS 就能读到:
// 浏览器控制台
window.__NUXT__.config.public.cacheAesKey // 直接拿到密钥
window.__NUXT__.config.public.apiKey
拿到密钥就能解 cookie / localStorage / 请求体 — 加密形同虚设。这是所有纯前端加密的固有局限,不是 framework 的设计失误:客户端要解密就必须能拿到密钥,密钥要发给客户端就必然能被反编译看见。
真正的安全靠什么
| 想防什么 | 真正的防御 |
|---|---|
| 中间人窃听传输内容 | HTTPS / TLS(不是 framework 加密) |
| 后端识别非法请求 | 后端鉴权:token 校验 / 请求签名校验 |
| 数据库泄露后明文可读 | 字段级加密(key 在 HSM/KMS,不在前端 bundle) |
| 防止用户篡改本地数据 | 后端再验证一遍(前端加密拦不住,只能拖延几秒) |
那 framework 的客户端加密还有什么用
仍然有意义但价值有限的几个场景:
- 防止 DevTools Cookies / Local Storage 面板一眼看到敏感字段 勾选"记住我"后,密码在 localStorage 里是密文而非明文 JSON — 路人甲不能扫一眼就拿走。
- 防止 cookie 内容随每个请求飞出去时被中间链路(log / proxy)顺手记录明文 token / userInfo 是密文,HTTPS 之外的链路(如内网日志)抓到的也是密文。
- 拦住自动化爬虫的 "low-effort" 攻击 爬虫不解 AES,原文搜不到关键词。专门盯着的攻击者花 30 秒就能反编译,没什么用。
设计建议
把 framework 加密当成 obfuscation,不要当作安全屏障。
- ✅ 用
useCookie/useLocal/useSession存登录态、用户偏好、UI 缓存 — obfuscation 带来的边际收益就够了。 - ✅ 用 framework 请求加密 — 防 log 明文 + 防 low-effort 爬虫。
- ❌ 不要把"加密了"当成可以放敏感字段的理由。 密码必须靠 HTTPS + 后端校验 + 用户主动选择("记住我")的多重防御组合。
- ❌ 不要在前端做"业务敏感数据加密后存数据库"的设计 — 那是后端字段级加密的活,密钥不该出现在前端。
已规划的演进
- AES-CBC → AES-GCM(已搁置,详见 framework#2 关闭评论):后端框架需兼容老项目、ECB 加密不能换,而 Web Crypto API 原生不支持 ECB,迁移整体搁置;待后端框架升级大版本时重新评估。
- 客户端密钥协商(不在规划):技术上可以用 ECDH 在登录时协商一份 session 密钥,避免硬编码。但工程成本远大于收益(HTTPS 已经解决 99% 的传输安全),目前不做。
相关文档
- 自动登录 + Token 过期重登链路 — 登录态持久化的完整链路
- request 模块 — 请求加密的工作原理