企业微信审批事件回调的安全验证与Java HMAC-SHA256校验实现
企业微信在审批状态变更时,会向配置的回调URL推送事件通知。为防止伪造请求,企业微信要求接收方必须校验请求头中的msg_signature,该签名基于token、timestamp、nonce和消息体内容,使用HMAC-SHA256算法生成。若校验失败,应拒绝处理。本文基于wlkankan.cn.verify包,完整实现安全验证逻辑,并提供可复用的工具类。
企业微信签名生成规则
根据官方文档,msg_signature计算公式为:
msg_signature = SHA1( token + timestamp + nonce + encrypted_msg )
但注意:实际使用的是 HMAC-SHA256 ,密钥为 token,数据为 timestamp + "\n" + nonce + "\n" + msg(含换行符)。这是常见误区。
签名验证工具类
java
package wlkankan.cn.verify;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class WeComSignatureVerifier {
public static boolean verify(String token, String timestamp, String nonce, String body, String signature) {
if (token == null || timestamp == null || nonce == null || body == null || signature == null) {
return false;
}
try {
String expectedSignature = generateSignature(token, timestamp, nonce, body);
return java.security.MessageDigest.isEqual(
expectedSignature.getBytes(StandardCharsets.UTF_8),
signature.getBytes(StandardCharsets.UTF_8)
);
} catch (Exception e) {
return false;
}
}
private static String generateSignature(String token, String timestamp, String nonce, String msg)
throws Exception {
String data = String.join("\n", timestamp, nonce, msg);
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(token.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKey);
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
}
}

Spring Boot控制器集成
在wlkankan.cn.controller中接收回调并校验:
java
package wlkankan.cn.controller;
import wlkankan.cn.verify.WeComSignatureVerifier;
import wlkankan.cn.service.ApprovalEventService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/wecom/callback")
public class ApprovalCallbackController {
@Value("${wecom.callback.token}")
private String callbackToken;
private final ApprovalEventService eventService;
public ApprovalCallbackController(ApprovalEventService eventService) {
this.eventService = eventService;
}
@PostMapping("/approval")
public String handleApprovalEvent(
@RequestHeader("msg_signature") String msgSignature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestBody String requestBody) {
if (!WeComSignatureVerifier.verify(callbackToken, timestamp, nonce, requestBody, msgSignature)) {
// 签名不合法,返回空或错误码(企业微信要求非200即重试)
return ""; // 企业微信文档建议非法请求直接返回空
}
// 解析XML或JSON(企业微信审批事件为XML)
ApprovalEvent event = parseApprovalEvent(requestBody);
eventService.process(event);
return "success"; // 必须返回"success"字符串
}
private ApprovalEvent parseApprovalEvent(String xml) {
// 使用Dom4j或Jackson XML解析
return XmlParser.parse(xml, ApprovalEvent.class);
}
}
ApprovalEvent模型示例
java
package wlkankan.cn.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "xml")
public class ApprovalEvent {
private String ToUserName;
private String FromUserName;
private Long CreateTime;
private String MsgType;
private String Event;
private String SpNo; // 审批单号
private String SpStatus; // APPROVED/REJECTED
// getters/setters
public String getSpNo() { return SpNo; }
public String getSpStatus() { return SpStatus; }
}
安全增强:防重放攻击
即使签名正确,攻击者仍可能重放旧请求。需校验timestamp是否在合理窗口内(如5分钟):
java
package wlkankan.cn.verify;
public class TimestampValidator {
private static final long MAX_TIME_DIFF_MS = 5 * 60 * 1000; // 5分钟
public static boolean isValidTimestamp(String timestampStr) {
try {
long timestamp = Long.parseLong(timestampStr) * 1000L; // 企业微信时间戳为秒
long now = System.currentTimeMillis();
return Math.abs(now - timestamp) <= MAX_TIME_DIFF_MS;
} catch (NumberFormatException e) {
return false;
}
}
}
在控制器中增加校验:
java
// 在 handleApprovalEvent 方法中
if (!TimestampValidator.isValidTimestamp(timestamp)) {
return "";
}
配置与部署
在application.yml中配置token:
yaml
wecom:
callback:
token: "your_secure_token_here"
确保该token与企业微信管理后台【应用管理】->【接收消息】中配置的Token完全一致。
通过wlkankan.cn.verify模块实现的HMAC-SHA256校验与时间戳防重放机制,有效保障了企业微信审批回调接口的安全性,防止未授权调用与数据篡改,满足生产环境安全要求。