如何安全加解密API响应JSON?寻求适配技术方案
可行的API响应加密/前端解密方案
你提到的bcrypt属于单向哈希算法,只能加密不能解密,完全不适合你的双向加解密需求。下面是基于对称加密算法的落地方案,推荐用AES-256-GCM(兼顾安全性和性能),直接上代码和关键说明:
核心逻辑
后端对响应的敏感字段(或整个JSON)进行加密,返回包含加密内容、初始化向量(IV)和认证标签的字符串;前端拿到后用相同密钥解密,还原原始数据。
后端加密实现(Node.js示例)
用Node.js内置crypto模块,无需额外安装依赖:
const crypto = require('crypto'); // 密钥用32字节(对应AES-256),从环境变量读取,绝对不能硬编码 const ENCRYPTION_KEY = Buffer.from(process.env.ENCRYPTION_KEY, 'hex'); // GCM模式推荐12字节的IV,每次加密必须生成新的 const IV_LENGTH = 12; // 单个字符串加密函数 function encrypt(text) { const iv = crypto.randomBytes(IV_LENGTH); const cipher = crypto.createCipheriv('aes-256-gcm', ENCRYPTION_KEY, iv); let encrypted = cipher.update(text, 'utf8', 'hex'); encrypted += cipher.final('hex'); // 把IV和认证标签一起返回,前端解密必须用这两个值 const authTag = cipher.getAuthTag().toString('hex'); return `${iv.toString('hex')}:${authTag}:${encrypted}`; } // 加密响应对象的指定字段 function encryptResponse(rawData) { return { abc_key: encrypt(rawData.abc_key), cde_key: encrypt(rawData.cde_key) }; } // 在API接口中使用 app.get('/api/secure-data', (req, res) => { const rawResponse = { abc_key: 'sdlnf-2343-325sdgdssg', cde_key: 'lkgh-3453-dtjdd-32423' }; res.json(encryptResponse(rawResponse)); });
前端解密实现
方案1:原生Web Crypto API(推荐,无依赖)
// 密钥和后端保持一致,转成ArrayBuffer格式 const ENCRYPTION_KEY = hexToBuffer(process.env.REACT_APP_ENCRYPTION_KEY); function hexToBuffer(hexStr) { return new Uint8Array(hexStr.match(/.{1,2}/g).map(byte => parseInt(byte, 16))).buffer; } async function decrypt(encryptedStr) { const [ivHex, authTagHex, encryptedHex] = encryptedStr.split(':'); const iv = hexToBuffer(ivHex); const authTag = hexToBuffer(authTagHex); const encryptedData = hexToBuffer(encryptedHex); // 导入密钥 const key = await window.crypto.subtle.importKey( 'raw', ENCRYPTION_KEY, { name: 'AES-GCM' }, false, ['decrypt'] ); // 解密并转回字符串 const decryptedBuffer = await window.crypto.subtle.decrypt( { name: 'AES-GCM', iv, tag: authTag }, key, encryptedData ); return new TextDecoder().decode(decryptedBuffer); } // 调用示例 async function fetchSecureData() { const res = await fetch('/api/secure-data'); const encryptedData = await res.json(); const decryptedData = { abc_key: await decrypt(encryptedData.abc_key), cde_key: await decrypt(encryptedData.cde_key) }; console.log('解密后数据:', decryptedData); }
方案2:crypto-js库(兼容旧浏览器)
先安装依赖:npm install crypto-js
import CryptoJS from 'crypto-js'; const ENCRYPTION_KEY = CryptoJS.enc.Hex.parse(process.env.REACT_APP_ENCRYPTION_KEY); function decrypt(encryptedStr) { const [ivHex, authTagHex, encryptedHex] = encryptedStr.split(':'); const iv = CryptoJS.enc.Hex.parse(ivHex); const authTag = CryptoJS.enc.Hex.parse(authTagHex); const encryptedData = CryptoJS.enc.Hex.parse(encryptedHex); const decrypted = CryptoJS.AES.decrypt( { ciphertext: encryptedData, authTag }, ENCRYPTION_KEY, { iv, mode: CryptoJS.mode.GCM, padding: CryptoJS.pad.NoPadding } ); return decrypted.toString(CryptoJS.enc.Utf8); } // 使用方式和方案1一致
关键注意事项
- 密钥安全:后端密钥必须存在环境变量中,前端密钥通过构建工具注入(比如React的
REACT_APP_前缀变量),但纯前端场景下密钥可能被反编译获取,这种情况建议结合HTTPS+JWT,或考虑后端代理解密。 - IV唯一性:每次加密必须生成新的随机IV,绝不能重复使用同一IV和密钥组合,否则会泄露密钥。
- 完整性校验:GCM模式的认证标签必须和加密内容一起传递,前端解密时会自动验证,防止数据被篡改。
- 加密范围:只加密敏感字段即可,无需加密整个JSON,减少性能开销。
内容的提问来源于stack exchange,提问作者Amaarockz
相关产品推荐
相关产品推荐

