您现在的位置是:网站首页 > 前端加密存储方案文章详情

前端加密存储方案

前端加密存储的必要性

前端加密存储是保护用户敏感数据的第一道防线。浏览器环境存在诸多安全隐患,如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];
  }
});

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步