当前位置: 首页 > news >正文

前后端通信加解密(Web Crypto API )

前端使用 ts,后端使用 node,要求 node版本大于18,本人用的 22
前端 encrypt.ts

/*** 使用 Web Crypto API 进行 AES-GCM 加密和解密* 注意:密钥应该从环境变量或配置中获取,不要硬编码*/// 加密密钥(应该是32字节,256位)
// 在实际项目中,这个密钥应该从环境变量或安全配置中获取
const ENCRYPTION_KEY = import.meta.env.VITE_ENCRYPTION_KEY
/*** 将字符串密钥转换为 CryptoKey*/
async function getKey(keyString: string): Promise<CryptoKey> {const encoder = new TextEncoder()const keyData = encoder.encode(keyString)// 确保密钥是32字节(256位)const keyArray = new Uint8Array(32)const sourceKey = new Uint8Array(keyData.slice(0, 32))keyArray.set(sourceKey)return crypto.subtle.importKey('raw',keyArray,{name: 'AES-GCM',length: 256,},false,['encrypt', 'decrypt'],)
}/*** 加密数据* @param data - 要加密的数据(可以是对象或字符串)* @returns 加密后的字符串(base64格式,包含iv)*/
export async function encrypt(data: string | object): Promise<string> {try {const cryptoKey = await getKey(ENCRYPTION_KEY)// 将数据转换为字符串const dataString = typeof data === 'string' ? data : JSON.stringify(data)const encoder = new TextEncoder()const dataBuffer = encoder.encode(dataString)// 生成随机 IV(初始化向量)const iv = crypto.getRandomValues(new Uint8Array(12))// 加密数据const encryptedData = await crypto.subtle.encrypt({name: 'AES-GCM',iv: iv,},cryptoKey,dataBuffer,)// 将 IV 和加密数据合并const combined = new Uint8Array(iv.length + encryptedData.byteLength)combined.set(iv, 0)combined.set(new Uint8Array(encryptedData), iv.length)// 转换为 base64 字符串(使用更安全的方式处理大数组)const binaryString = Array.from(combined, (byte) => String.fromCharCode(byte)).join('')return btoa(binaryString)} catch (error) {console.error('加密失败:', error)throw new Error('数据加密失败')}
}/*** 解密数据* @param encryptedData - 加密后的数据(base64格式)* @returns 解密后的原始数据(如果是JSON字符串,需要手动解析)*/
export async function decrypt(encryptedData: string): Promise<string> {try {const cryptoKey = await getKey(ENCRYPTION_KEY)// 从 base64 解码const binaryString = atob(encryptedData)const combined = new Uint8Array(binaryString.length)for (let i = 0; i < binaryString.length; i++) {combined[i] = binaryString.charCodeAt(i)}// 提取 IV 和加密数据const iv = combined.slice(0, 12)const data = combined.slice(12)// 解密数据const decryptedData = await crypto.subtle.decrypt({name: 'AES-GCM',iv: iv,},cryptoKey,data,)// 转换为字符串const decoder = new TextDecoder()return decoder.decode(decryptedData)} catch (error) {console.error('解密失败:', error)throw new Error('数据解密失败')}
}/*** 加密请求参数(自动处理对象)* @param data - 请求参数对象* @returns 加密后的字符串*/
export async function encryptRequestData(data: any): Promise<string> {return encrypt(data)
}/*** 解密响应数据(自动解析JSON)* @param encryptedData - 加密的响应数据* @returns 解密后的对象*/
export async function decryptResponseData(encryptedData: string): Promise<any> {const decrypted = await decrypt(encryptedData)try {return JSON.parse(decrypted)} catch {return decrypted}
}

前端加解密eg:

请求加密
await encryptRequestData(config.data)
响应解密
await decryptResponseData(response.data.data)

后端 encrypt.ts

require("dotenv").config();
const { webcrypto } = require("crypto");// 在 Node.js < 19.0.0 中,TextEncoder 和 TextDecoder 是全局可用的
// 但为了代码的明确性和兼容性,可以从 'util' 模块导入
const { TextEncoder, TextDecoder } = require("util");const ENCRYPTION_KEY = process.env.VITE_ENCRYPTION_KEY;/*** 将字符串密钥转换为 CryptoKey*/
async function getKey(keyString) {if (!keyString) {throw new Error("加密密钥未配置");}const encoder = new TextEncoder();const keyData = encoder.encode(keyString);// 确保密钥是32字节(256位)const keyArray = new Uint8Array(32);const sourceKey = new Uint8Array(keyData.slice(0, 32));keyArray.set(sourceKey);return webcrypto.subtle.importKey("raw",keyArray,{name: "AES-GCM",length: 256,},false,["encrypt", "decrypt"]);
}/*** 加密数据* @param data - 要加密的数据(可以是对象或字符串)* @returns 加密后的字符串(base64格式,包含iv)*/
async function encrypt(data) {try {const cryptoKey = await getKey(ENCRYPTION_KEY);// 将数据转换为字符串const dataString = typeof data === "string" ? data : JSON.stringify(data);const encoder = new TextEncoder();const dataBuffer = encoder.encode(dataString);// 生成随机 IV(初始化向量)const iv = webcrypto.getRandomValues(new Uint8Array(12));// 加密数据const encryptedData = await webcrypto.subtle.encrypt({name: "AES-GCM",iv: iv,},cryptoKey,dataBuffer);// 将 IV 和加密数据合并const combined = new Uint8Array(iv.length + encryptedData.byteLength);combined.set(iv, 0);combined.set(new Uint8Array(encryptedData), iv.length);// 转换为 base64 字符串(使用更安全的方式处理大数组)const binaryString = Array.from(combined, (byte) =>String.fromCharCode(byte)).join("");return btoa(binaryString);} catch (error) {console.error("加密失败:", error);throw new Error("数据加密失败");}
}/*** 解密数据* @param encryptedData - 加密后的数据(base64格式)* @returns 解密后的原始数据(如果是JSON字符串,需要手动解析)*/
async function decrypt(encryptedData) {try {const cryptoKey = await getKey(ENCRYPTION_KEY);// 从 base64 解码const combined = Buffer.from(encryptedData, "base64");// 提取 IV 和加密数据const iv = combined.slice(0, 12);const data = combined.slice(12);// 解密数据const decryptedData = await webcrypto.subtle.decrypt({name: "AES-GCM",iv: iv,},cryptoKey,data);// 转换为字符串const decoder = new TextDecoder();return decoder.decode(decryptedData);} catch (error) {console.error("解密失败:", error);throw new Error("数据解密失败");}
}/*** 解密请求参数(自动解析JSON)* @param encryptedData - 加密的请求数据* @returns 解密后的对象*/
async function decryptRequestData(encryptedData) {const decrypted = await decrypt(encryptedData);try {return JSON.parse(decrypted);} catch {return decrypted;}
}/*** 加密响应数据(自动处理对象)* @param data - 响应数据对象* @returns 加密后的字符串*/
async function encryptResponseData(data) {return encrypt(data);
}// 导出函数
module.exports = {encrypt,decrypt,decryptRequestData,encryptResponseData,
};

实例:

后端请求解密:
await decryptRequestData(data);
后端响应加密:
const rpd = await encryptResponseData({...response.data,});
// 返回第三方接口的响应res.json(rpd);
http://www.dtcms.com/a/593593.html

相关文章:

  • 基于数字图像相关(DIC)技术的机械臂自动化焊接残余应力全场变形高精度测量
  • XTOM-TRANSFORM-ROB:面向大尺寸构件的移动式非接触三维扫描与自动化质量检测
  • PyWinInspect:pywinauto 桌面自动化开发伴侣,集成 Inspect 元素检查 + 定位代码自动生成,效率大提升!
  • 个人做什么网站软件技术专升本难吗
  • HarmonyOS:ArkUI栅格布局系统(GridRow/GridCol)
  • 电商设计师常用的网站wordpress 获取分类地址
  • 开放签电子签章系统3.2版本更新内容
  • 电子商务的网站建设过程辽宁沈阳网站建设
  • C++ 设计模式《统计辅助功能》
  • 【技术分享】ComfyUI中protobuf版本兼容性问题的优雅解决方案:猴子补丁实战
  • Redis 高级篇(未完结1/3)
  • 华为OD机试 真题 - 【国际移动用户识别码(IMSI)匹配】 - 双机位A卷 (Python C++ JAVA JS GO)
  • 自动更新工期触发器(MYSQL)
  • 企业网站建设的方式有哪些方式网页设计版权怎么写
  • 关键词解释:范数(Norm)
  • 用Python生成个性化的电子邮件签名
  • [PowerShell入门教程] 第2天:变量、管道、对象操作与执行策略详解
  • 做网站运营的职业生涯规划wordpress 水印插件
  • 护照阅读器在酒店行业的应用
  • 继承的概念及使用
  • 建网站的地址手工制作小船
  • 技术选型深度评估:“六行神算”平台在医疗AI项目中的架构适配性
  • VLAN 和 VXLAN
  • PC微信 device uuid 算法
  • 外国网站的浏览器下载网站程序是什么意思
  • 【Docker多节点部署】基于“配置即身份“理念的 Docker 多节点 StarRocks 高可用集群自动化部署方案
  • 如何选择适合企业的数据仓库建模工具?​
  • Ethernet ip转SPI嵌入式板卡-让机器人与单片机互相联动
  • 免费推广网站大全下载安装南山网站-建设深圳信科
  • 【ZeroRange WebRTC】OpenSSL 与 WebRTC:原理、集成与实践指南