service worker 无法加密缓存,因 cache api 不支持流式加解密且 web crypto 不兼容 response.body;敏感数据应禁用缓存、用 indexeddb + web crypto 主动加密,并由用户控制密钥。

Service Worker 本身不提供加密能力,也无法直接对 Cache Storage 中的资源进行加密存储。浏览器的 Cache API(caches.open()、cache.put() 等)只接受标准 Request/Response 对象,其内容以明文形式存于本地磁盘(受浏览器沙箱保护),开发者无法在写入缓存前自动加密、读取时自动解密。
这意味着:
- 若用户能物理访问设备并导出浏览器缓存目录(如 Chrome 的
Cache或CacheStorage文件夹),且具备一定逆向能力,静态缓存的 HTML、JS、JSON 等响应体可被直接读取; - Service Worker 脚本运行在受限沙箱中,无权调用 Web Crypto API 对
Response.body进行流式加解密后再交给 Cache API —— 因为Response.body是ReadableStream,而Crypto.subtle.encrypt()不支持流式处理,且cache.put()要求传入完整Response,无法插入加密中间层。
所以,“通过 Service Worker 拦截并加密本地敏感缓存”这一目标技术上不可行,不是策略问题,而是浏览器平台限制。
真实可行的替代方案
✅ 敏感数据根本不进 Cache Storage
-
API 响应中的 token、用户身份、支付信息、私有文档内容等,禁止缓存
在fetch事件中明确拦截/api/类请求,跳过caches.match()和cache.put():if (url.pathname.startsWith('/api/') || request.method !== 'GET') { return fetch(request); // 直连网络,不缓存 } - 对含敏感字段的 JSON 接口,服务端应返回
Cache-Control: no-store, no-cache,Service Worker 尊重该头(caches.match()默认不匹配带no-store的响应)。
✅ 静态资源可缓存,但需剥离敏感逻辑
- HTML/CSS/JS 可预缓存(
install阶段),但不得内嵌密钥、token、未脱敏用户数据 - 用户专属内容(如“欢迎,张三”)必须由前端 JS 在运行时通过安全上下文(如
window.clientInformation或已认证的 IndexedDB 数据)动态注入,而非由后端直出并缓存。
✅ 真正需要离线加密存储?用 IndexedDB + Web Crypto
- 将敏感结构化数据(如离线草稿、加密笔记)存入
IndexedDB,写入前用Crypto.subtle.encrypt()加密,密钥派生自用户密码(PBKDF2)或设备绑定密钥(navigator.credentials.create()生成的PublicKeyCredential); - 解密密钥绝不硬编码,不存于 Service Worker 或 localStorage;
- 注意:Web Crypto 密钥不能跨 Origin 共享,且需用户主动触发(如登录输入密码),无法全自动静默加解密。
✅ 强化边界防护(降低窃取风险)
- 启用
Clear-Site-Data响应头,在用户登出时清除所有缓存与存储; - 设置
Cache-Control: private, max-age=0, must-revalidate控制缓存生命周期; - 避免在
sw.js中暴露任何密钥、API 地址或业务逻辑分支(它本身是公开可读的 JS 文件)。
总结一句话
Service Worker 是缓存调度员,不是保险柜。想防离线窃取,核心思路是:敏感数据不落地缓存,必须落地则走 IndexedDB + 主动加密,且密钥由用户可控。把加密责任强加给 Service Worker,既违背设计初衷,也突破当前 Web 平台能力边界。










