使用AES-CBC + HMAC-SHA256实现前后端请求安全验证

AES-CBC + HMAC-SHA256 加密验证方案,下面是该方案二等 优点缺点 表格,适用于文档、评审或技术选型说明。

✅ 优点表格:AES-CBC + HMAC-SHA256 加密验证方案

类别优点说明
🔐 安全性使用 AES-CBC 对称加密使用 AES-128-CBC 是可靠且广泛接受的对称加密方式。
随机生成 IV每次加密生成新的 IV,有效防止密文重放与模式识别。
HMAC-SHA256 签名增强完整性校验,防止中间人篡改密文。
加密前先签名验证防止不合法密文触发解密报错或被利用。
💡 灵活性签名算法可切换支持从 HMAC-SHA256 切换为其他如 SHA-512。
密钥可由 token 派生动态生成密钥,便于用户级安全控制。
前端跨平台适用适用于 Web、小程序、移动端等多平台前端环境。
🔁 可部署性可嵌入代理层Nginx + Lua 可提前拦截无效请求,节省后端资源。
🧩 多语言兼容Node.js、Python、Lua 等实现简单支持常见语言和平台,易于团队协作与系统整合。

❌ 缺点表格:AES-CBC + HMAC 签名方案的局限

类别缺点说明
⚙️ 实现复杂度实现逻辑较多需要额外编码 IV 管理、HMAC 签名、前后端一致性等细节。
🔁 重放防护默认无时间戳或 nonce重放攻击不可防,需要自行引入 timestamp + nonce 参数。
🔑 密钥依赖密钥动态性带来兼容问题一旦 token 失效或更换,旧数据将无法解密。
📦 数据随机访问不支持局部解密AES-CBC 是块加密,不能随机访问或解密数据片段。
🕒 不适合长期缓存密文随机性增加校验复杂度每次加密结果不同,不适合用于长期静态存储的校验场景。

🧭 补充建议(可选扩展)

增强点建议
防重放在签名前加上时间戳 + nonce 字段,防止多次使用旧数据
加密模式升级可考虑迁移到 AES-GCM,天然支持认证(AEAD)
秘钥管理密钥建议动态派生(如基于用户会话、JWT claims 等)

下面是该方案的实现详细代码:


✅ 前端 JavaScript:frontend.js

// === frontend.js ===
// 前端:使用 AES-CBC 加密 + HMAC-SHA256 签名
import aesjs from 'aes-js';
import CryptoJS from 'crypto-js';function aaa(token) {return aesjs.utils.utf8.toBytes(token.padEnd(16, '0').slice(0, 16));
}function generateRandomIV() {let iv = new Uint8Array(16);window.crypto.getRandomValues(iv);return iv;
}function getHmacSHA256(keyBytes, messageHex) {const keyHex = CryptoJS.enc.Hex.parse(aesjs.utils.hex.fromBytes(keyBytes));const hmac = CryptoJS.HmacSHA256(messageHex, keyHex);return hmac.toString(CryptoJS.enc.Hex);
}function encryptWithMac(token, plaintext) {const key = aaa(token);const iv = generateRandomIV();const textBytes = aesjs.utils.utf8.toBytes(plaintext);const padded = aesjs.padding.pkcs7.pad(textBytes);const aesCbc = new aesjs.ModeOfOperation.cbc(key, iv);const encryptedBytes = aesCbc.encrypt(padded);const ivHex = aesjs.utils.hex.fromBytes(iv);const ciphertextHex = aesjs.utils.hex.fromBytes(encryptedBytes);const fullDataHex = ivHex + ciphertextHex;const mac = getHmacSHA256(key, fullDataHex);return {data: fullDataHex,mac: mac};
}const token = 'abc123';
const msg = 'hello world';
const result = encryptWithMac(token, msg);
console.log(JSON.stringify(result));

✅ Node.js 后端验证:backend_node.js

// backend_node.js
const crypto = require('crypto');function deriveKey(token) {return Buffer.from(token.padEnd(16, '0').slice(0, 16));
}function verifyEncryptedData(token, dataHex, macHex) {const key = deriveKey(token);const iv = Buffer.from(dataHex.slice(0, 32), 'hex');const ciphertext = Buffer.from(dataHex.slice(32), 'hex');// 验证 HMACconst hmac = crypto.createHmac('sha256', key);hmac.update(dataHex);const expectedMac = hmac.digest('hex');if (expectedMac !== macHex) {throw new Error('MAC 验证失败');}// 解密const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);decipher.setAutoPadding(true);let decrypted = decipher.update(ciphertext, null, 'utf8');decrypted += decipher.final('utf8');return decrypted;
}// 示例
const token = 'abc123';
const { data, mac } = JSON.parse(/* 前端结果 */ '{"data": "...", "mac": "..."}');try {const plaintext = verifyEncryptedData(token, data, mac);console.log('解密成功:', plaintext);
} catch (e) {console.error(e.message);
}

✅ Python 后端验证:backend_python.py

# backend_python.py
from Crypto.Cipher import AES
from Crypto.Hash import HMAC, SHA256
from binascii import unhexlifydef derive_key(token: str) -> bytes:return token.ljust(16, '0')[:16].encode()def verify_encrypted_data(token, data_hex, mac_hex):key = derive_key(token)iv = unhexlify(data_hex[:32])ciphertext = unhexlify(data_hex[32:])# 验证 HMACh = HMAC.new(key, digestmod=SHA256)h.update(data_hex.encode())try:h.hexverify(mac_hex)except ValueError:raise ValueError('MAC 验证失败')# 解密cipher = AES.new(key, AES.MODE_CBC, iv)padded = cipher.decrypt(ciphertext)pad_len = padded[-1]return padded[:-pad_len].decode()# 示例
token = 'abc123'
data = '...'  # 前端 data
mac = '...'   # 前端 mactry:print('解密成功:', verify_encrypted_data(token, data, mac))
except Exception as e:print('失败:', e)

✅ Nginx + Lua (OpenResty):aes_verify.lua

-- aes_verify.lua
local aes = require "resty.aes"
local hmac = require "resty.hmac"
local str = require "resty.string"
local cjson = require "cjson"ngx.req.read_body()
local body = ngx.req.get_body_data()
local json = cjson.decode(body)
local data = json.data
local mac = json.mac
local token = ngx.var.http_authorization:sub(8)local key = token .. string.rep("0", 16 - #token)
key = key:sub(1, 16)local hmac_obj = hmac:new(key, hmac.ALGOS.SHA256)
hmac_obj:update(data)
local expected_mac = str.to_hex(hmac_obj:final())if expected_mac ~= mac thenngx.status = 401ngx.say("MAC 验证失败")return ngx.exit(401)
endlocal iv = str.to_hex(data:sub(1, 32))
local cipher = data:sub(33)
local aes_cbc = aes:new(key, nil, aes.cipher(128, "cbc"), { iv = iv })
local decrypted = aes_cbc:decrypt(str.from_hex(cipher))
local pad = string.byte(decrypted:sub(-1))
decrypted = decrypted:sub(1, -pad-1)ngx.say("验证通过,原文: ", decrypted)

配置片段:

location /api/secure-data {content_by_lua_file /etc/nginx/lua/aes_verify.lua;proxy_pass http://backend_service;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/904940.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Veins同时打开SUMO和OMNeT++的GUI界面

进入 Veins 工程目录(即包含 sumo-launchd.py 的目录),打开终端设置 SUMO_HOME 环境变量(指向你安装的 SUMO 路径): export SUMO\_HOME/home/veins/src/sumo-1.11.0编译 Veins 工程(包含 OMNeT…

suricata之日志截断

一、背景 在suricata的调试过程中,使用SCLogXXX api进行信息的输出,发现输出的日志被截断了,最开始以为是解析逻辑有问题,没有解析完整,经过排查后,发现SCLogXXX api内部进行了长度限制,最长2K…

navicat 如何导出数据库表 的这些信息 字段名 类型 描述

navicat 如何导出数据库表 的这些信息 字段名 类型 描述 数据库名字 springbootmt74k 表名字 address SELECT COLUMN_NAME AS 字段名,COLUMN_TYPE AS 类型,COLUMN_COMMENT AS 描述 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA springbootmt74k AND TABLE_NAME a…

LVGL图像导入和解码

LVGL版本:8.1 概述 在LVGL中,可以导入多种不同类型的图像: 经转换器生成的C语言数组,适用于页面中不常改变的固定图像。存储系统中的外部图像,比较灵活,可以通过插卡或从网络中获取,但需要配置…

【Web前端开发】HTML基础

Web前端开发是用来直接给用户呈现一个一个的网页,主要包含实现用户的结构(HTML)、样式(CSS)、交互(JavaScript)。然而一个软件通常是由后端和前端完成的。可以查阅文档:HTML 教程 (w…

MySQL 8.0 单节点部署与一主两从架构搭建实战

前言:在数据驱动的时代,数据库作为数据存储与管理的核心组件,其架构的选择与配置对系统的性能、可用性和扩展性至关重要。MySQL 作为一款广泛应用的开源关系型数据库,凭借其稳定的性能和丰富的功能,深受开发者和企业的…

数据库故障排查全攻略:从实战案例到体系化解决方案

一、引言:数据库故障为何是技术人必须攻克的 "心腹大患" 在数字化时代,数据库作为企业核心数据资产的载体,其稳定性直接决定业务连续性。据 Gartner 统计,企业每小时数据库 downtime 平均损失高达 56 万美元&#xff0…

牛客周赛round91

C 若序列为1 4 5 7 9 1 2 3,1 9一定大于1 1或1 4...所以只需要记录当前数之前数字的最大值,然后遍历取max即可,所以对于上面的序列有效的比较为1 9,2 9,3 9取max 代码 //求大于当前数的最大值,然后…

【MCAL】TC397+EB-tresos之I2c配置实战(同步、异步)

I2C总线是Philips公司在八十年代初推出的一种串行、半双工的总线,主要用于近距离、低速的芯片之间的通信。本篇文章首先从理论讲起,介绍了英飞凌TC3x系列芯片对应MCAL中对I2C驱动的定义与介绍,建议读者在阅读本篇文章之前对I2C有个简单的认识…

深拷贝与浅拷贝:理解 Python 中的对象复制机制

深拷贝与浅拷贝:理解 Python 中的对象复制机制 在 Python 编程中,对象的复制是一个常见的操作。然而,很多初学者在处理对象复制时会遇到困惑,尤其是在涉及到复杂数据结构(如列表、字典、自定义对象等)时。…

BeanPostProcessor和AOP

BeanPostProcessor Spring中有一个接口Oredr的getOrder()方法,这个方法返回值是一个int类型,Spring容器会根据这个方法的返回值 对容器的多个Processor对象从小到大排序,创建Bean时候依次执行他们的方法,也就是说getOrder()方法的…

拒绝服务攻击(DoS/DDoS/DRDoS)详解:洪水猛兽的防御之道

在数字时代,服务的可用性是衡量一个在线系统成功与否的关键指标之一。然而,存在一类被称为"拒绝服务攻击" (Denial of Service, DoS) 的网络攻击,其主要目的就是通过各种手段耗尽目标服务器或网络的资源,使其无法响应正…

小刚说C语言刷题—1078求恰好使s=1+1/2+1/3+…+1/n的值大于X时n的值

1.题目描述 求恰好使 s11/21/3⋯1/n 的值大于 X 时 n 的值。( 2≤x≤10 ) 输入 输入只有一行,包括 1个整数 X 。 输出 输出只有一行(这意味着末尾有一个回车符号),包括 1 个整数。 样例 输入 2 输出 4 2.参考代码(C语言…

深度学习中的目标检测:从 PR 曲线到 AP

深度学习中的目标检测:从 PR 曲线到 AP 在目标检测任务中,评估模型的性能是非常重要的。通过使用不同的评估指标和标准,我们可以量化模型的准确性与效果。今天我们将重点讨论 PR 曲线(Precision-Recall Curve)、平均精…

MySQL 1366 - Incorrect string value:错误

MySQL 1366 - Incorrect string value:错误 错误如何发生发生原因: 解决方法第一种尝试第二种尝试 错误 如何发生 在给MySQL添加数据的时候发生了下面的错误 insert into sys_dept values(100, 0, 0, 若依科技, 0, 若依, 15888888888, ryqq.com, 0,…

[ctfshow web入门] web70

信息收集 使用cinclude("php://filter/convert.base64-encode/resourceindex.php");读取的index.php error_reporting和ini_set被禁用了,不必管他 error_reporting(0); ini_set(display_errors, 0); // 你们在炫技吗? if(isset($_POST[c])){…

Linux在web下http加密和配置虚拟主机及动态页面发布

web服务器的数据加密 1.简介:由于http协议以明文方式发送,不提供任何方式的数据加密,也不适合传输一些重要的信息,如银行卡号、密码等,解决该缺陷设计了安全套接字层超文本传输协议https; 2.https的握手流…

uni-app,小程序中的addPhoneContact,保存联系人到手机通讯录

文章目录 方法详解简介 基本语法参数说明基础用法使用示例平台差异说明注意事项最佳实践 方法详解 简介 addPhoneContact是uni-app框架提供的一个实用API,用于向系统通讯录添加联系人信息。这个方法在需要将应用内的联系人信息快速保存到用户设备通讯录的场景下非…

NHANES稀有指标推荐:HALP score

文章题目:Associations of HALP score with serum prostate-specific antigen and mortality in middle-aged and elderly individuals without prostate cancer DOI:10.3389/fonc.2024.1419310 中文标题:HALP 评分与无前列腺癌的中老年人血清…

【django.db.utils.OperationalError: unable to open database file】

解决platform.sh 环境下,无法打开数据库问题 场景 在platform.sh 执行python manage.py createsuperuser是提示 django.db.utils.OperationalError: unable to open database file 错误 原因 由于settings.py文件中 本地数据库配置在线上配置后,导致…