JS AES加密详解

前言

AES(Advanced Encryption Standard,高级加密标准)是目前Web接口加密里使用最多的对称加密算法。对称加密意味着加密和解密使用同一个密钥 Key,前端加密、后端解密(或者反过来),在前后端报文保护、参数加密场景中非常普及。

重要前置提醒:

前端JS里的AES不存在绝对安全。密钥如果写死在前端代码中,只要被逆向拿到key和iv,密文就能直接解开。AES只是用来防抓包直读明文,不能防止专业逆向。高安全场景一般做法:AES加密业务数据,再用RSA把AES密钥加密后传输。

本文会讲清楚AES核心概念、模式、填充规则,同时给出两套实现:经典的 CryptoJS 版本 + 浏览器原生 Web Crypto API(推荐新标准),附带踩坑说明,也是爬虫逆向中识别AES加密的核心参考。

一、AES基础概念

AES是分组加密算法,固定分组长度为 128 bit(16字节),根据密钥长度分为三类:

  • AES-128:key 16字节(最常用)
  • AES-192:key 24字节
  • AES-256:key 32字节

字节换算:1字节 = 8bit,所以 AES128 key = 16个字符(UTF8)。

1. 工作模式(Mode)【逆向重点区分】

不同模式加密流程完全不一样,抓包逆向时首先要判断模式:

  1. ECB :电子密码本模式。不推荐使用,不安全。没有IV,相同明文+相同key加密结果永远一样,容易被分析。很多老网站遗留代码在用。
  2. CBC :密码分组链接模式。Web中最常见,需要额外传入 IV(偏移向量,固定16字节);前一组密文参与下一组明文加密,打乱重复特征。
  3. GCM :伽罗瓦/计数器模式。现代推荐,带认证,除了加密还会产出authTag,能够校验密文是否被篡改;很多新项目、小程序、App配套接口在用。>

还有CFB、OFB、CTR等,网页里相对少见。

2. 填充(Padding)

AES是分组加密,明文长度如果不是分组大小(16字节)的整数倍,就需要填充补齐。

  • PKCS7Padding:Web默认主流填充,CryptoJS默认就是这个(很多后端Java/Python也是PKCS7)
  • ZeroPadding:补0填充,兼容性差,很少用
  • NoPadding:不填充,要求明文长度必须是16字节整数倍,否则直接报错

坑点:前后端填充方式不一致,会直接解密报错、报bad padding。

3. IV 偏移向量

CBC / GCM 模式必须要有IV,固定16字节。

  • IV不需要保密,但不能固定写死不变(安全规范),最好每次加密随机生成,随密文一起传给后端;
  • 逆向经常遇到网站写死IV:1234567890123456,这是典型偷懒写法。

4. 编码格式

加密出来是二进制字节流,网络传输不能直接发二进制,一般会转成:

  • Base64:最普遍
  • Hex(16进制字符串):部分系统使用

二、CryptoJS 实现(项目最常见,逆向高频)

说明:CryptoJS是第三方库,不是浏览器原生API,老项目大量使用,也是爬虫逆向遇到最多的AES实现。

安装:npm install crypto-js 或者直接引入CDN脚本。

AES-CBC 加密解密示例

复制代码
import CryptoJS from 'crypto-js'

// 配置
const key = CryptoJS.enc.Utf8.parse('1234567890123456') // 16字节 key AES-128
const iv = CryptoJS.enc.Utf8.parse('1234567890123456')  // 16字节 iv

// 加密函数
function aesEncrypt(plainText) {
  const encrypted = CryptoJS.AES.encrypt(plainText, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })
  return encrypted.toString() // 默认输出 base64
}

// 解密函数
function aesDecrypt(cipherText) {
  const decrypted = CryptoJS.AES.decrypt(cipherText, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  })
  return decrypted.toString(CryptoJS.enc.Utf8)
}

// 测试
const txt = 'hello aes 测试内容'
const secret = aesEncrypt(txt)
console.log('密文base64:', secret)
console.log('解密结果:', aesDecrypt(secret))

ECB模式示例(仅用于兼容老系统,不推荐生产)

复制代码
function aesEcbEncrypt(plainText) {
  const encrypted = CryptoJS.AES.encrypt(plainText, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  })
  return encrypted.toString()
}

ECB 不需要 iv 参数。

AES-GCM 示例(带tag校验)

GCM会额外生成一个authTag,后端解密时必须带上tag校验完整性:

复制代码
function aesGcmEncrypt(plainText) {
  const encrypted = CryptoJS.AES.encrypt(plainText, key, {
    iv: iv,
    mode: CryptoJS.mode.GCM,
    padding: CryptoJS.pad.NoPadding
  })
  return {
    ciphertext: encrypted.ciphertext.toString(CryptoJS.enc.Base64),
    tag: encrypted.getAuthTag().toString(CryptoJS.enc.Base64)
  }
}

三、浏览器原生 Web Crypto API(现代标准,无第三方依赖)

window.crypto.subtle 是浏览器内置密码学API,推荐新项目优先使用,性能更好、安全策略更规范;注意:只能在 HTTPS / localhost 环境下使用,http普通页面会被禁用。

原生API写法比较繁琐,区分字节数组,不再像CryptoJS一样直接传字符串。

复制代码
/**
 * Web Crypto AES-CBC
 * @param {string} plainText 明文
 * @param {string} keyStr 16字节key
 * @param {string} ivStr 16字节iv
 * @returns {Promise<string>} base64密文
 */
async function webCryptoAesCbcEncrypt(plainText, keyStr, ivStr) {
  const encoder = new TextEncoder()
  const keyRaw = encoder.encode(keyStr)
  const ivRaw = encoder.encode(ivStr)
  const dataRaw = encoder.encode(plainText)

  // 导入密钥
  const key = await crypto.subtle.importKey(
    'raw',
    keyRaw,
    { name: 'AES-CBC' },
    false,
    ['encrypt', 'decrypt']
  )
  // 加密
  const buf = await crypto.subtle.encrypt(
    { name: 'AES-CBC', iv: ivRaw },
    key,
    dataRaw
  )
  // ArrayBuffer 转 base64
  return btoa(String.fromCharCode(...new Uint8Array(buf)))
}

async function webCryptoAesCbcDecrypt(base64Cipher, keyStr, ivStr) {
  const encoder = new TextEncoder()
  const keyRaw = encoder.encode(keyStr)
  const ivRaw = encoder.encode(ivStr)
  const cipherBuf = Uint8Array.from(atob(base64Cipher), c => c.charCodeAt(0))

  const key = await crypto.subtle.importKey(
    'raw',
    keyRaw,
    { name: 'AES-CBC' },
    false,
    ['encrypt', 'decrypt']
  )
  const plainBuf = await crypto.subtle.decrypt(
    { name: 'AES-CBC', iv: ivRaw },
    key,
    cipherBuf
  )
  return new TextDecoder().decode(plainBuf)
}

// 调用示例
;(async () => {
  const key = '1234567890123456'
  const iv = '1234567890123456'
  const cipher = await webCryptoAesCbcEncrypt('测试原生AES', key, iv)
  console.log('原生加密密文:', cipher)
  const plain = await webCryptoAesCbcDecrypt(cipher, key, iv)
  console.log('原生解密:', plain)
})()

四、逆向时如何判断是AES?

做爬虫逆向遇到接口密文,可以通过下面特征快速识别:

  1. 密文是标准Base64字符串,长度经常是24、32、44、64等;
  2. JS代码里出现关键词:CryptoJS.AES、mode.CBC、Pkcs7、iv;
  3. 代码里固定取出16位字符串作为iv、16/32位字符串作为key;
  4. GCM模式会额外返回/传递 tag 参数。

常见逆向卡点:

  • key、iv不是直接明文字符串,是hex、base64解码之后才拿到;
  • key经过md5、sha256处理后截取前16字节当做AES key;
  • 后端是Java,默认PKCS7,前端填错填充直接解密失败。

五、生产环境最佳实践 & 避坑清单

  1. ❌ 禁止前端硬编码固定Key,禁止ECB模式上线;
  2. ✅ 每次加密随机生成16字节IV,iv随密文一起传给后端;
  3. ✅ 敏感业务:AES加密报文,RSA公钥加密AES的临时key;
  4. ✅ GCM优先于CBC,自带防篡改校验;
  5. ✅ 统一约定:编码UTF8、填充PKCS7、输出Base64;
  6. ❌ 不要自己手写AES底层算法,极易出漏洞,优先成熟库;
  7. ⚠️ Web Crypto API 在http页面、文件本地打开(file://)直接不可用。

六、补充:Node.js 内置crypto模块(后端配套)

很多时候前端CryptoJS-AES,后端是Node crypto,配套互通,简单示例:

复制代码
const crypto = require('crypto')
function nodeAesEncrypt(text, key, iv) {
  const cipher = crypto.createCipheriv('aes-128-cbc', key, iv)
  let r = cipher.update(text, 'utf8', 'base64')
  r += cipher.final('base64')
  return r
}

保证 key、iv、模式、填充完全一致,前后端才能互通解密。

结语

AES本身是安全强度很高的分组加密算法,风险从来不在于AES算法本身,而在于密钥的分发和保管。前端只能作为传输层防护手段,用来防止明文直接被抓包查看,不能用来保护最高等级的机密数据。

在逆向工作中,只要定位到key、iv、mode、padding这四要素,AES密文就可以直接还原;在业务开发中,合理搭配RSA+AES混合加密方案,才是Web接口加密的成熟方案。

相关推荐
信息安全失业大专人员1 小时前
每日了解一个智能体-WorkBuddy
开发语言·ai·c#·智能体
4ever.ov02 小时前
精学C++第一站 从命名空间到引用:C++入门核心语法全梳理(13000字长文)
开发语言·c++·clion
小杨互联网2 小时前
Go 现代 CLI 工具离线镜像合集
开发语言·后端·golang·开源·go·命令行
揽星河..2 小时前
【C语言】数组
c语言·开发语言·算法
FRing032 小时前
JavaScript入门到精通三十三(异常处理、call方法、apply方法、bind方法、防抖、节流)
开发语言·前端·javascript
geovindu2 小时前
rust: Semaphore Pattern
开发语言·后端·设计模式·rust·代理模式·企业级信号量模式·同步型模式
纪念 2293 小时前
C++ 算法(模拟)
开发语言·c++·算法
niucloud-admin3 小时前
NIUCLOUD PHP SAAS上门家政使用文档--服务订单:评价列表
开发语言·php
jktantan3 小时前
(二)Vue 3 的 attrs 不是响应式:el-form 扩展属性同步的三种方案
前端·javascript·vue.js·element-plus