接口签名Webhook验签,这个Java工具类13个方法常量时间比对

简介: 这是一个专为Java(JDK17+)设计的安全工具类,提供HmacMD5/SHA1/SHA256/SHA512四种算法的签名、验签与防篡改功能,支持十六进制/Base64/原始字节三种输出格式,含常量时间比对,新接入推荐HmacSHA256。

📋 目录

一、工具类功能

给接口签名、Webhook 验签、令牌防篡改算 HMAC 并常量时间比对,支持 HmacMD5 到 HmacSHA512 四种算法,输出十六进制、Base64 或原始字节,新接入一律选 HmacSHA256。

二、所需环境

JDK 17或以上

三、方法与调用示例(按需调用)

🔢 方法序号:1

🎯 方法用途:

  • 算 HmacMD5 并给小写十六进制串,输出固定 32 位
  • 只为还在用 HmacMD5 的遗留系统保留,新接入别选它

🧩 方法定义:public static String hmacMd5(String data, String key)

🗣️ 入参解释:public static String hmacMd5(正文, 密钥)

📤 返回值解释:String,32 位小写十六进制的 MAC

💡 边界口径:

  • 正文与密钥都按 UTF-8 取字节,双方必须约定同一套编码
  • 空正文是合法输入,只有 null 被拒绝
  • 正文为 null 抛 IllegalArgumentException,密钥为 null 或空白同样抛
  • MD5 已经不该再用于新签名方案,能用 SHA-256 就用 SHA-256

🧪 方法示例:

  • hmacMd5(BODY, SECRET) 拿到 d6dcbdcd2d45983d049e4e7003fc3b95
  • 正文传 null 抛 待认证数据不能为null
  • 密钥给空白串抛 密钥不能为null或空白

🔢 方法序号:2

🎯 方法用途:

  • 算 HmacSHA1 并给小写十六进制串,输出 40 位
  • 部分开放平台的历史签名要求是它,新接入不选

🧩 方法定义:public static String hmacSha1(String data, String key)

🗣️ 入参解释:public static String hmacSha1(正文, 密钥)

📤 返回值解释:String,40 位小写十六进制的 MAC

💡 边界口径:

  • 与 hmacMd5 同一条路径,只是算法换成 HmacSHA1
  • 参数校验、UTF-8 取字节、空正文合法这些口径完全一致

🧪 方法示例:

  • hmacSha1(BODY, SECRET) 拿到 61dfc9cbe98cfafc960917405584cfa91564b3fc,长度 40

🔢 方法序号:3

🎯 方法用途:

  • 算 HmacSHA256 并给小写十六进制串,新接入的推荐选择
  • 接口签名、Webhook 校验、令牌防篡改都从它起步

🧩 方法定义:public static String hmacSha256(String data, String key)

🗣️ 入参解释:public static String hmacSha256(正文, 密钥)

📤 返回值解释:String,64 位小写十六进制的 MAC

💡 边界口径:

  • 等价于 hmacHex(HMAC_SHA256, data, key),输出长度固定 64 位
  • 同一输入反复计算结果稳定,可以拿它做缓存键与重放对比
  • Mac 实例非线程安全,本类每次调用新建,可并发使用

🧪 方法示例:

  • hmacSha256(BODY, SECRET) 拿到 d237de3947138319e4b6d18eaca7d0e26a86816f95b9dd3e0eb6fa21482ea191
  • hmacSha256("", SECRET) 拿到 2dadd0e065f61424af1a9e2ab71633c0e7bc6a18b34f06fd1da80ef0ca9e7150,空正文照样出签名
  • 上一步的空串签名再交给 verifyHex 验,拿到 true

🔢 方法序号:4

🎯 方法用途:

  • 算 HmacSHA512 并给小写十六进制串,输出 128 位
  • 对方协议点名要 SHA-512,或想要更长摘要时用

🧩 方法定义:public static String hmacSha512(String data, String key)

🗣️ 入参解释:public static String hmacSha512(正文, 密钥)

📤 返回值解释:String,128 位小写十六进制的 MAC

💡 边界口径:

  • 原始字节固定 64 个,编码成十六进制才是 128 位,签名字段要留够宽度
  • 口径与其余具名入口一致,只是摘要更长

🧪 方法示例:

  • hmacSha512(BODY, SECRET) 拿到 823a8add31a9b58ea2ddf4ea4cdc318925b4aa853739715ff63c873787d43a373f8950506d61b858855a9dbb6050585f05ce01b36772fbf94e3516c2805940c4
  • hmac("HmacSHA512", "payload-with-中文", "secret-key").length 拿到 64

🔢 方法序号:5

🎯 方法用途:

  • 指定算法名算 HMAC 出十六进制,算法名不必逐字对得上 JCA
  • 配置项里存的常常是 HMAC-SHA256、hmac_sha256 这类产品名,靠它归一命中

🧩 方法定义:public static String hmacHex(String algorithm, String data, String key)

🗣️ 入参解释:public static String hmacHex(算法名, 正文, 密钥)

📤 返回值解释:String,小写十六进制的 MAC

💡 边界口径:

  • 归一规则是去首尾空白、转大写、去掉 _ 与 -,四个算法的别名都能命中
  • 别名表之外的名字抛 IllegalArgumentException 并列出支持范围,不做模糊猜测
  • 算法名为 null 或空白同样抛异常
  • 结果是稳定值,同一输入换台机器也算得一样

🧪 方法示例:

  • hmacHex(HmacUtils.HMAC_SHA256, BODY, SECRET) 拿到 d237de3947138319e4b6d18eaca7d0e26a86816f95b9dd3e0eb6fa21482ea191
  • hmacHex("HMAC-SHA256", BODY, SECRET) 也拿到 d237de3947138319e4b6d18eaca7d0e26a86816f95b9dd3e0eb6fa21482ea191
  • hmacHex("hmac_sha256", BODY, SECRET) 同样拿到 d237de3947138319e4b6d18eaca7d0e26a86816f95b9dd3e0eb6fa21482ea191
  • hmacHex("SM4", BODY, SECRET) 抛 不支持的HMAC算法: SM4,仅支持 HmacMD5/HmacSHA1/HmacSHA256/HmacSHA512
  • hmacHex(" ", BODY, SECRET) 抛 HMAC算法不能为null或空白

🔢 方法序号:6

🎯 方法用途:

  • 指定算法算 HMAC 并输出标准 Base64,含 padding
  • 签名要放进 header 或 JSON 字段、嫌十六进制太长时用这一版

🧩 方法定义:public static String hmacBase64(String algorithm, String data, String key)

🗣️ 入参解释:public static String hmacBase64(算法名, 正文, 密钥)

📤 返回值解释:String,标准 Base64 形态的 MAC

💡 边界口径:

  • 与 hmacHex 是同一份字节的两种编码,长度约为十六进制的四分之三
  • 出的是标准字母表;对方给 URL 安全或无 padding 的写法,验签侧仍然认
  • 参数校验口径同 hmacHex

🧪 方法示例:

  • hmacBase64(HmacUtils.HMAC_SHA256, BODY, SECRET) 拿到 0jfeOUcTgxnkttGOrKfQ4mqGgW+Vud0+Drb6IUguoZE=
  • verifyBase64(HmacUtils.HMAC_SHA512, BODY, SECRET, b64) 拿到 true,b64 就是 hmacBase64(HmacUtils.HMAC_SHA512, BODY, SECRET) 的结果

🔢 方法序号:7

🎯 方法用途:

  • 字节形态的十六进制出口,密钥含 0x00 与高字节也不失真
  • 数据是已序列化的报文、文件内容时走这个入口,别先转成字符串

🧩 方法定义:public static String hmacHex(String algorithm, byte[] data, byte[] key)

🗣️ 入参解释:public static String hmacHex(算法名, 字节正文, 字节密钥)

📤 返回值解释:String,小写十六进制的 MAC

💡 边界口径:

  • 字节按原样进 MAC 计算,不做任何字符集解释
  • 空密钥数组被拒:空密钥的 MAC 没有意义,不该静默算出一个值
  • 正文是空数组则合法

🧪 方法示例:

  • hmacHex("HmacSHA256", raw, rawKey) 拿到 b759f847ecaa80661dc79a4a11012258261078bced6a4d27148041b96dac3632,rawKey 是含 0x00 的四个字节
  • hmacHex("HmacSHA256", new byte[]{1}, new byte[0]) 抛 密钥字节不能为null或空数组
  • 字符串入口 hmacHex("HmacSHA256", "payload-with-中文", "secret-key") 与字节入口比对,拿到 true

🔢 方法序号:8

🎯 方法用途:

  • 字节形态的 Base64 出口,二进制内容要放进文本字段时用
  • 密钥本身是字节数组的配置项走这一版

🧩 方法定义:public static String hmacBase64(String algorithm, byte[] data, byte[] key)

🗣️ 入参解释:public static String hmacBase64(算法名, 字节正文, 字节密钥)

📤 返回值解释:String,标准 Base64 形态的 MAC

💡 边界口径:

  • 与字节版 hmacHex 同一份字节,只是换了编码
  • 校验口径与字节版 hmacHex 一致

🧪 方法示例:

  • hmacBase64("HmacSHA256", raw, rawKey) 拿到 t1n4R+yqgGYdx5pKEQEiWCYQeLztak0nFIBBuW2sNjI=

🔢 方法序号:9

🎯 方法用途:

  • 取 MAC 的原始字节,编码方式与后续派生自己决定
  • 要把签名再拼进密钥派生、或自己转成别的编码时用

🧩 方法定义:public static byte[] hmac(String algorithm, String data, String key)

🗣️ 入参解释:public static byte[] hmac(算法名, 正文, 密钥)

📤 返回值解释:byte[],MAC 原始字节,SHA-256 是 32 个

💡 边界口径:

  • 返回的数组与 hmacHex、hmacBase64 是同一份字节
  • 数组可写可改,不想被下游改动就自己复制一份
  • 字符串入口固定按 UTF-8 取字节

🧪 方法示例:

  • hmac(HmacUtils.HMAC_SHA256, BODY, SECRET) 拿到 32 字节
  • hmacHex(HmacUtils.HMAC_SHA256, BODY, SECRET).length() == macBytes.length * 2 拿到 true,两种出口同源

🔢 方法序号:10

🎯 方法用途:

  • 字节形态取 MAC 原始字节,用于原始报文与文件内容
  • 二进制协议要比字节签名时先用它拿值

🧩 方法定义:public static byte[] hmac(String algorithm, byte[] data, byte[] key)

🗣️ 入参解释:public static byte[] hmac(算法名, 字节正文, 字节密钥)

📤 返回值解释:byte[],MAC 原始字节

💡 边界口径:

  • 与字符串入口取的是同一套 UTF-8 字节,两侧结果一致
  • 空密钥数组抛 IllegalArgumentException,空正文数组合法

🧪 方法示例:

  • Arrays.equals(macBytes, stringPath) 拿到 true,两个入口算出的是同一份 MAC

🔢 方法序号:11

🎯 方法用途:

  • 校验十六进制 MAC,常量时间比较,忽略预期值的大小写与空白
  • 对方给的签名可能是大写、可能带分组空格时用它,别直接比字符串

🧩 方法定义:public static boolean verifyHex(String algorithm, String data, String key, String expectedHex)

🗣️ 入参解释:public static boolean verifyHex(算法名, 正文, 密钥, 预期签名)

📤 返回值解释:boolean,比对通过返回 true

💡 边界口径:

  • 比的是解码后的字节,d237… 与 D237… 判成同一个签名
  • 预期值里的空白会被剥掉,分组换行不影响判定;正文本身的空白不参与忽略
  • 预期值是非法十六进制或长度为奇数时判不通过,返回 false 而不是抛异常
  • 预期值为 null 或空白属参数问题,抛 IllegalArgumentException

🧪 方法示例:

  • verifyHex(HmacUtils.HMAC_SHA512, BODY, SECRET, HmacUtils.hmacHex(HmacUtils.HMAC_SHA512, BODY, SECRET).toUpperCase()) 拿到 true
  • verifyHex(HmacUtils.HMAC_SHA512, BODY + " ", SECRET, HmacUtils.hmacHex(HmacUtils.HMAC_SHA512, BODY, SECRET)) 拿到 false,正文多一个空格就判不过
  • 预期值截成奇数长度 d237de3 时拿到 false
  • 预期值传 null 抛 预期MAC不能为null或空白

🔢 方法序号:12

🎯 方法用途:

  • 校验 Base64 MAC,标准与 URL 安全、有无需 padding、折行写法都能识别
  • 网关把签名头折过行、前端给的串没补 = 时用这一版

🧩 方法定义:public static boolean verifyBase64(String algorithm, String data, String key, String expectedBase64)

🗣️ 入参解释:public static boolean verifyBase64(算法名, 正文, 密钥, 预期签名)

📤 返回值解释:boolean,比对通过返回 true

💡 边界口径:

  • 解码依次试标准、URL 安全、补 padding 三种写法,解开再比字节
  • 三种写法都解不开就判不通过返回 false,不把网关错误记成系统故障
  • 预期值为 null 或空白属参数问题,抛 IllegalArgumentException

🧪 方法示例:

  • verifyBase64(HmacUtils.HMAC_SHA512, BODY, SECRET, b64) 标准形态拿到 true
  • 同一个 MAC 换成 URL 安全且无 padding 的 urlSafeNoPadding 仍拿到 true
  • 中间插了回车换行的 folded 也拿到 true
  • 预期值是垃圾串时拿到 false

🔢 方法序号:13

🎯 方法用途:

  • 直接比对 MAC 原始字节,二进制协议与自定义编码报文用
  • 手里已经是 byte[] 时省掉再编码成字符串的一步

🧩 方法定义:public static boolean verify(String algorithm, byte[] data, byte[] key, byte[] expectedMac)

🗣️ 入参解释:public static boolean verify(算法名, 字节正文, 字节密钥, 预期字节)

📤 返回值解释:boolean,字节完全一致返回 true

💡 边界口径:

  • 用 MessageDigest.isEqual 常量时间比较,长度不同直接判不通过
  • 预期字节为 null 返回 false 而不抛异常,这点与两个字符串版验签入口不同
  • 正文与密钥的校验口径同 hmac 字节入口

🧪 方法示例:

  • verify(HmacUtils.HMAC_SHA256, BODY.getBytes(StandardCharsets.UTF_8), SECRET.getBytes(StandardCharsets.UTF_8), macBytes) 拿到 true
  • 预期字节传 null 拿到 false,不抛异常

四、工具类源码(可直接复制)

📦 源码文件

相关文章
|
云安全 安全 网络安全
|
15天前
|
JSON 程序员 数据格式
最新版Notepad++下载、安装、配置保姆级教程(附官网安装包)
Notepad++ 是一款免费开源、轻量快速的 Windows 文本编辑器,支持多标签、语法高亮、代码折叠与宏录制,体积小、启动快、资源占用低,兼容 x64/x32/ARM 架构,是程序员和文字工作者的高效利器。
3650 0
|
8天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
2046 2
|
14天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
2459 46
|
11天前
|
Web App开发 人工智能 前端开发
2026 年 AI 浏览器怎么选?Ego Lite、Tabbit、Chrome DevTools MCP 深度对比,开发者到底该用哪个?
2026年AI浏览器选型指南:Ego Lite专注多Agent协同(Mac优先),Tabbit国产首选,原生支持Windows与Codex控制;Chrome DevTools MCP非浏览器而是开发者利器,深度集成Console/Network/Performance调试能力,让AI真正“看懂并验证”前端代码。
1472 3
|
9天前
|
开发者 索引
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
Open Plugin Market 是一个开放插件索引平台,收录800+优质DSH插件,支持分类浏览、智能推荐与随机发现。无需安装市场,粘贴索引地址即可一键接入,网页版直访 dshopen.org,助力小开发者被看见。(239字)
1957 1
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
|
7天前
|
人工智能 Linux API
Magpie, 轻量本地AI网关!免费Token用不完!
Magpie 是开源AI编程模型调度网关,上线一月获1.8万Star。它通过本地高性能网关统一托管多平台API密钥、账号与免费额度,实现跨Agent的模型秒级切换、静默额度轮换与资源复用,显著降低碎片化管理成本。(239字)
Magpie, 轻量本地AI网关!免费Token用不完!
|
8天前
|
安全 应用服务中间件 Go
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
PHP2Shell 双 RCE 已遭在野利用:WordPress、Drupal 全在射程内,nginx 其实另有洞。拆成因与修复顺序
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
|
4天前
|
人工智能 安全 API
2026 年阿里云双 11|百炼大模型 API 指南:免费 Token 领取、API Key 生成、代码调用实战教程
对于零基础的AI开发者、技术爱好者和小型开发团队来说,低成本、低门槛调用主流大模型接口,是开启AI项目原型开发的必经之路。百炼大模型服务平台汇集了百余款主流大模型,面向新用户提供大规模免费推理额度,不需要预先充值,即可完成文本生成、逻辑推理、代码编写、多模态解析等各类开发验证工作。很多新手在初次接触平台时,常常遇到不清楚免费额度规则、不知道如何生成API‑Key、环境配置错误、调用接口持续报错等一系列问题。
604 1

热门文章

最新文章