Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Concept

Webhook 签名验证

第三方回调的 HMAC 签名验证和防篡改机制。

Last updated

第三方服务通过 Webhook 回调通知支付结果、签章状态、消息事件。回调端点暴露在公网,必须验证签名防止伪造请求。

验证流程

业务处理签名验证器回调端点第三方服务业务处理签名验证器回调端点第三方服务alt[签名匹配][签名不匹配]POST /callback (body + signature header)验证签名(body, signature, secret)✓ 通过处理业务返回 success✗ 拒绝返回 fail

Payment 域的回调验签

// ① 回调端点验签
app.MapPost("/callback/alipay", async (HttpContext ctx, IPaymentProvider payment) =>
{
var body = await new StreamReader(ctx.Request.Body).ReadToEndAsync();
var payload = new CallbackPayload
{
Body = body,
QueryString = ctx.Request.QueryString.Value,
};
// ② 验证签名并解析回调内容
var result = await payment.VerifyCallbackAsync(payload);
if (!result.IsSuccess)
return Results.Text("fail"); // ③ 验签失败返回 fail
var data = result.Data!;
// ④ 处理业务逻辑...
return Results.Text("success"); // ⑤ 必须返回 success,否则会重复通知
});

VerifyCallbackAsync 内部调用 AlipayHttpClient.VerifyCallback 做 RSA2 签名验证:

public bool VerifyCallback(Dictionary<string, string> callbackParams)
{
// ① 提取签名和签名类型
var sign = callbackParams["sign"];
var signType = callbackParams["sign_type"];
// ② 按支付宝规则排序参数(排除 sign/sign_type)
var sortedParams = callbackParams
.Where(p => p.Key != "sign" && p.Key != "sign_type")
.OrderBy(p => p.Key, StringComparer.Ordinal)
.Select(p => $"{p.Key}={p.Value}");
var content = string.Join("&", sortedParams);
// ③ 用支付宝公钥验证 RSA2 签名
return _signer.Verify(content, sign);
}

Webhooks 基础设施

Bitzsoft.Integrations.Webhooks 提供通用的 Webhook 验证基础设施:

HmacWebhookVerifier

public class HmacWebhookVerifier : IWebhookVerifier
{
public bool Verify(WebhookPayload payload, string signature, string secret)
{
// ① 用 HMAC-SHA256 计算摘要
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload.RawBody));
// ② 安全比较(防止时序攻击)
return CryptographicEquals(computedHash, Convert.FromHexString(signature));
}
}

IWebhookVerifierResolver

public interface IWebhookVerifierResolver
{
IWebhookVerifier? Resolve(string providerId);
}

按 Provider ID 解析对应的验证器。

收件箱(至少一次投递)

Webhook 基础设施提供收件箱保证至少一次投递:

public interface IWebhookInboxStore
{
Task<bool> TryAckAsync(string messageId); // 幂等去重
Task EnqueueAsync(WebhookMessage message);
}

InMemoryWebhookInboxStore 仅供开发,生产环境应使用持久化存储。

各域回调验签模式

签名算法验签入口
Payment.AlipayRSA2IPaymentProvider.VerifyCallbackAsync
Payment.WeChatPayHMAC-SHA256IPaymentProvider.VerifyCallbackAsync
ElectronicSignature厂商各自实现IElectronicSignatureCallbackParser
TeamWork厂商各自实现IWebhookVerifierResolver

安全要点

规则原因
签名比较使用恒定时间比较防止时序攻击
验签失败返回明确的 fail让第三方知道需要重试
验签通过后才处理业务防止伪造请求触发业务逻辑
处理完成后返回约定的成功标识否则第三方会重复通知
Webhook Secret 与 API Secret 分开管理最小权限原则

相关

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%