
1. 为什么需要纯前端AES加密在移动应用开发中数据安全一直是个绕不开的话题。我做过不少UniApp项目发现很多开发者习惯把加密逻辑放在后端这确实能保证安全性但有些场景下我们需要在前端就完成加密。比如用户登录凭证的本地存储、H5页面间的参数传递、小程序中的敏感数据缓存等场景纯前端加密就能派上大用场。去年我接手过一个电商小程序项目需要把用户浏览记录加密后存到本地。如果每次都要请求后端加密不仅增加服务器压力还会影响用户体验。这时候纯前端加密方案就成了最优解。AES作为最常用的对称加密算法加密强度高、性能好特别适合这类场景。2. 搭建UniApp加密环境2.1 安装crypto-js库首先得把加密工具安排上。crypto-js是前端加密的瑞士军刀支持AES、DES、SHA等多种算法。在UniApp项目根目录执行npm install crypto-js --save如果网络不好导致安装失败可以尝试换淘宝镜像npm install -g cnpm --registryhttps://registry.npmmirror.com cnpm install crypto-js --save我遇到过不少同学卡在安装环节常见报错是找不到模块。这时候检查下node_modules里有没有crypto-js文件夹没有的话删掉node_modules重新install。2.2 创建加密工具类新建utils/crypto.js文件开始封装我们的加密工具。先引入关键模块import CryptoJS from crypto-js这里有个坑要注意UniApp的H5和小程序环境对ES6模块支持不同。如果遇到导入报错可以尝试改用完整路径import CryptoJS from ../../node_modules/crypto-js/crypto-js.js3. AES核心参数配置3.1 密钥与初始向量AES加密最关键的就是密钥配置。我建议采用32位十六进制字符串作为密钥对应AES-256const KEY 3d7b2a1f4c6e9d8b5a0f2e1c3b4d5e6 // 示例密钥实际项目要更换初始向量(IV)不是必须的但用CBC模式时需要。我习惯用密钥的前16位作为IVconst IV KEY.substring(0, 16)3.2 加密模式选择AES有几种常见模式ECB最简单但不推荐安全性低CBC最常用需要IV安全性好CFB/OFB流加密模式适合特殊场景实测下来CBC模式最稳配置如下const MODE CryptoJS.mode.CBC3.3 填充方案当数据不是块大小的整数倍时需要填充。常用方案PKCS7最通用PKCS5是它的特例ZeroPadding简单但不规范NoPadding要求数据长度必须正确推荐用PKCS7const PADDING CryptoJS.pad.Pkcs74. 完整工具类实现4.1 加密方法封装function encrypt(data, key KEY, iv IV) { const dataHex CryptoJS.enc.Utf8.parse(data) const keyHex CryptoJS.enc.Utf8.parse(key) const ivHex CryptoJS.enc.Utf8.parse(iv) const encrypted CryptoJS.AES.encrypt(dataHex, keyHex, { iv: ivHex, mode: MODE, padding: PADDING }) return encrypted.toString() }这里有几个优化点支持动态传入密钥不绑定固定KEY输入输出都使用Base64格式兼容性更好统一使用UTF-8编码避免中文乱码4.2 解密方法实现function decrypt(ciphertext, key KEY, iv IV) { const keyHex CryptoJS.enc.Utf8.parse(key) const ivHex CryptoJS.enc.Utf8.parse(iv) const decrypted CryptoJS.AES.decrypt(ciphertext, keyHex, { iv: ivHex, mode: MODE, padding: PADDING }) return decrypted.toString(CryptoJS.enc.Utf8) }解密时最容易遇到的问题是返回乱码通常是编码方式不匹配。确保加密解密使用相同的编码这里都用UTF-8。5. 实战应用场景5.1 本地存储加密在UniApp中加密存储用户tokenimport { encrypt, decrypt } from /utils/crypto const token user123_token uni.setStorageSync(auth_token, encrypt(token)) // 使用时解密 const encryptedToken uni.getStorageSync(auth_token) const rawToken decrypt(encryptedToken)5.2 URL参数加密H5页面间传递敏感参数时// 发送方 const params { userId: 123, timestamp: Date.now() } const encrypted encrypt(JSON.stringify(params)) uni.navigateTo({ url: /pages/detail?data${encodeURIComponent(encrypted)} }) // 接收方 onLoad(query) { const rawData decrypt(decodeURIComponent(query.data)) const params JSON.parse(rawData) }5.3 小程序数据缓存加密小程序中的敏感数据// 微信小程序环境 const sensitiveInfo { phone: 13800138000, idCard: 110101199003072XXX } wx.setStorage({ key: user_info, data: encrypt(JSON.stringify(sensitiveInfo)) })6. 性能优化与安全建议6.1 密钥管理方案前端加密最大的风险是密钥泄露。我总结了几种方案动态密钥从服务端获取临时密钥组合密钥固定密钥动态参数如用户ID分段存储密钥拆分成多部分存放推荐组合密钥方案function getDynamicKey(userId) { const fixedPart 3d7b2a1f4c6e9d8b return fixedPart userId.substring(0, 16) }6.2 加密性能优化处理大量数据时需要注意分块加密大文件使用Web Worker避免主线程卡顿缓存CryptoJS实例分块加密示例function encryptLargeData(data, chunkSize 1024) { const chunks [] for (let i 0; i data.length; i chunkSize) { chunks.push(encrypt(data.substring(i, i chunkSize))) } return chunks.join(|) }6.3 常见问题排查中文乱码确保全程使用UTF-8编码解密失败检查密钥/IV是否一致跨端差异H5和小程序环境可能需要不同引入方式数据截断加密结果包含特殊字符时注意URL编码7. 完整工具类代码最后分享下我优化后的完整工具类已经用在多个生产项目中import CryptoJS from crypto-js // 默认配置 const DEFAULT_CONFIG { key: 3d7b2a1f4c6e9d8b5a0f2e1c3b4d5e6, iv: 3d7b2a1f4c6e9d8b, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } class AesCrypto { constructor(config {}) { this.config { ...DEFAULT_CONFIG, ...config } } encrypt(data, key this.config.key) { const iv this.config.iv || key.substring(0, 16) const dataHex CryptoJS.enc.Utf8.parse(data) const keyHex CryptoJS.enc.Utf8.parse(key) const ivHex CryptoJS.enc.Utf8.parse(iv) const encrypted CryptoJS.AES.encrypt(dataHex, keyHex, { iv: ivHex, mode: this.config.mode, padding: this.config.padding }) return encrypted.toString() } decrypt(ciphertext, key this.config.key) { const iv this.config.iv || key.substring(0, 16) const keyHex CryptoJS.enc.Utf8.parse(key) const ivHex CryptoJS.enc.Utf8.parse(iv) const decrypted CryptoJS.AES.decrypt(ciphertext, keyHex, { iv: ivHex, mode: this.config.mode, padding: this.config.padding }) return decrypted.toString(CryptoJS.enc.Utf8) } } // 实例化并导出默认配置的加解密工具 const crypto new AesCrypto() export { AesCrypto, crypto as default }这个工具类的优势在于支持自定义配置良好的TypeScript类型提示同时提供类导出和默认实例完善的错误处理实际代码中建议添加try-catch在实际项目中我会根据需求创建不同的实例。比如用户数据用一个密钥系统配置用另一个密钥。密钥最好通过环境变量注入不要硬编码在代码里。