您现在的位置是:网站首页 > 前端加密存储方案文章详情
前端加密存储方案
陈川
【
前端安全
】
61214人已围观
6473字
前端加密存储的必要性
前端加密存储是保护用户敏感数据的第一道防线。浏览器环境存在诸多安全隐患,如XSS攻击、中间人攻击、本地存储泄露等。未加密的敏感数据一旦被窃取,可能导致用户隐私泄露、身份盗用等严重后果。2018年某社交平台就曾因前端存储的访问令牌未加密,导致数百万用户数据泄露。
常见前端存储方式分析
localStorage与sessionStorage
// 不安全的原始存储方式
localStorage.setItem('userToken', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
这两种存储方式虽然方便,但存在明显缺陷:
- 数据以明文形式存储
- 同源下的所有脚本都可访问
- 持久化存储可能被恶意扩展读取
IndexedDB
IndexedDB适合存储结构化数据,但同样存在安全问题:
const request = indexedDB.open('userDB');
request.onsuccess = (event) => {
const db = event.target.result;
const tx = db.transaction('tokens', 'readwrite');
const store = tx.objectStore('tokens');
store.put('rawData'); // 未加密数据
};
Cookie的安全属性
虽然可通过HttpOnly、Secure等属性增强安全性,但前端可读的cookie仍需加密:
document.cookie = `session=${encrypt(data)}; Secure; SameSite=Strict`;
加密算法选择与实践
Web Crypto API基础使用
现代浏览器原生支持的加密接口:
async function generateKey() {
return await window.crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
}
对称加密实现示例
AES-GCM模式推荐方案:
async function encryptData(data, key) {
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode(data);
const ciphertext = await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
encoded
);
return { iv, ciphertext };
}
非对称加密场景
适合敏感度极高的数据传输:
async function rsaEncrypt(data, publicKey) {
const encoded = new TextEncoder().encode(data);
return await window.crypto.subtle.encrypt(
{ name: "RSA-OAEP" },
publicKey,
encoded
);
}
密钥管理策略
动态密钥生成方案
const deriveKey = async (password, salt) => {
const keyMaterial = await window.crypto.subtle.importKey(
'raw',
new TextEncoder().encode(password),
{ name: 'PBKDF2' },
false,
['deriveKey']
);
return window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt,
iterations: 100000,
hash: 'SHA-256'
},
keyMaterial,
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
};
密钥分片存储技术
将主密钥拆分为多个部分:
function splitKey(key, parts, threshold) {
const keyBytes = new Uint8Array(key);
// 使用Shamir秘密共享算法实现
return shamir.split(keyBytes, parts, threshold);
}
综合实施方案
用户密码加密存储流程
async function secureStorePassword(password) {
// 生成盐值
const salt = crypto.getRandomValues(new Uint8Array(16));
// 派生密钥
const key = await deriveKey(password, salt);
// 加密数据
const encrypted = await encryptData(JSON.stringify({
password: await hashPassword(password)
}), key);
// 存储加密数据
localStorage.setItem('vault', JSON.stringify({
salt: Array.from(salt),
iv: Array.from(encrypted.iv),
ciphertext: Array.from(new Uint8Array(encrypted.ciphertext))
}));
}
敏感字段保护方案
class SecureStorage {
constructor(masterKey) {
this.masterKey = masterKey;
}
async setItem(key, value) {
const encrypted = await encryptData(value, this.masterKey);
localStorage.setItem(key, JSON.stringify({
iv: Array.from(encrypted.iv),
data: Array.from(new Uint8Array(encrypted.ciphertext))
}));
}
async getItem(key) {
const item = JSON.parse(localStorage.getItem(key));
if (!item) return null;
const decrypted = await decryptData(
new Uint8Array(item.data).buffer,
this.masterKey,
new Uint8Array(item.iv)
);
return new TextDecoder().decode(decrypted);
}
}
性能与安全权衡
加密操作性能优化
// 预生成密钥避免重复计算
let cachedKey = null;
async function getEncryptionKey() {
if (!cachedKey) {
cachedKey = await generateKey();
// 设置30分钟过期
setTimeout(() => { cachedKey = null }, 1800000);
}
return cachedKey;
}
选择性加密策略
根据数据敏感程度分级处理:
const SECURITY_LEVEL = {
LOW: 0, // 不加密
MEDIUM: 1, // 基础加密
HIGH: 2 // 强化加密
};
function encryptByLevel(data, level) {
switch(level) {
case SECURITY_LEVEL.MEDIUM:
return lightEncrypt(data);
case SECURITY_LEVEL.HIGH:
return strongEncrypt(data);
default:
return data;
}
}
防御进阶攻击
对抗内存扫描
function secureWipe(buffer) {
const view = new Uint8Array(buffer);
for (let i = 0; i < view.length; i++) {
view[i] = 0;
}
// 防止优化
window.crypto.getRandomValues(view);
}
反调试保护
const debuggerProtection = setInterval(() => {
if (typeof window.devtools !== 'undefined' ||
window.outerWidth - window.innerWidth > 200) {
clearInterval(debuggerProtection);
window.location.href = 'about:blank';
}
}, 1000);
浏览器扩展安全交互
安全的消息通信机制:
// 内容脚本
chrome.runtime.sendMessage({
type: 'ENCRYPT_REQUEST',
data: await encryptExtensionData(payload)
});
// 后台脚本
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === 'ENCRYPT_REQUEST') {
decryptExtensionData(request.data).then(sendResponse);
return true;
}
});
实时加密通信方案
WebSocket数据加密示例:
const ws = new WebSocket('wss://example.com');
ws.onmessage = async (event) => {
const encrypted = JSON.parse(event.data);
const decrypted = await decryptData(
new Uint8Array(encrypted.data).buffer,
currentKey,
new Uint8Array(encrypted.iv)
);
processData(decrypted);
};
async function sendEncrypted(data) {
const encrypted = await encryptData(data, currentKey);
ws.send(JSON.stringify({
iv: Array.from(encrypted.iv),
data: Array.from(new Uint8Array(encrypted.ciphertext))
}));
}
移动端特殊考量
React Native加密存储示例:
import { NativeModules } from 'react-native';
import CryptoJS from 'crypto-js';
const secureStore = async (key, value) => {
const encrypted = CryptoJS.AES.encrypt(
value,
deviceUniqueId
).toString();
await NativeModules.SecureStorage.setItem(key, encrypted);
};
审计与监控机制
加密操作日志记录:
const securityLogger = new Proxy(console, {
get(target, prop) {
if (['log', 'warn', 'error'].includes(prop)) {
return function(...args) {
const stack = new Error().stack;
sendToMonitoringService({
type: 'CRYPTO_LOG',
level: prop,
message: args.join(' '),
stack,
timestamp: Date.now()
});
target[prop].apply(target, args);
};
}
return target[prop];
}
});