浏览器端存储安全(LocalStorage/IndexedDB/Service Worker)最佳实践概述浏览器端存储需坚持数据最小化与可过期策略,对敏感数据采用加密与作用域限制,并治理离线缓存。加密存储封装async function deriveKey(secret: string): Promise<CryptoKey> { const enc = new TextEncoder().encode(secret) return await crypto.subtle.importKey('raw', enc, 'AES-GCM', false, ['encrypt', 'decrypt']) } async function encrypt(value: string, key: CryptoKey): Promise<string> { const iv = crypto.getRandomValues(new Uint8Array(12)) const data = new TextEncoder().encode(value) const ct = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, data) return `${btoa(String.fromCharCode(...iv))}.${btoa(String.fromCharCode(...new Uint8Array(ct)))}` } async function decrypt(payload: string, key: CryptoKey): Promise<string> { const [ivb64, ctb64] = payload.split('.') const iv = Uint8Array.from(atob(ivb64), c => c.charCodeAt(0)) const ct = Uint8Array.from(atob(ctb64), c => c.charCodeAt(0)) const pt = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ct) return new TextDecoder().decode(pt) } TTL与最小化type Entry = { value: string; expiresAt: number } function setWithTTL(k: string, v: string, ttlMs: number) { const e: Entry = { value: v, expiresAt: Date.now() + ttlMs } localStorage.setItem(k, JSON.stringify(e)) } function getWithTTL(k: string): string | null { const raw = localStorage.getItem(k) if (!raw) return null const e = JSON.parse(raw) as Entry if (Date.now() > e.expiresAt) { localStorage.removeItem(k); return null } return e.value } Service Worker缓存治理self.addEventListener('install', (event) => { event.waitUntil(caches.open('app-v1').then((cache) => cache.addAll(['/index.html', '/styles.css']))) }) self.addEventListener('fetch', (event) => { const url = new URL(event.request.url) if (!['/index.html', '/styles.css', '/script.js'].includes(url.pathname)) return event.respondWith(caches.match(event.request).then((res) => res || fetch(event.request))) }) 运维要点避免在LocalStorage存放长期令牌,优先使用安全Cookie对IndexedDB敏感集合进行加密与分区管理对Service Worker缓存启用版本与白名单路径控制通过加密封装、TTL与缓存治理,可提升浏览器端数据安全与可控性。

发表评论 取消回复