第三方服务通过 Webhook 回调通知支付结果、签章状态、消息事件。回调端点暴露在公网,必须验证签名防止伪造请求。
验证流程
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.Alipay | RSA2 | IPaymentProvider.VerifyCallbackAsync |
| Payment.WeChatPay | HMAC-SHA256 | IPaymentProvider.VerifyCallbackAsync |
| ElectronicSignature | 厂商各自实现 | IElectronicSignatureCallbackParser |
| TeamWork | 厂商各自实现 | IWebhookVerifierResolver |
安全要点
| 规则 | 原因 |
|---|---|
| 签名比较使用恒定时间比较 | 防止时序攻击 |
| 验签失败返回明确的 fail | 让第三方知道需要重试 |
| 验签通过后才处理业务 | 防止伪造请求触发业务逻辑 |
| 处理完成后返回约定的成功标识 | 否则第三方会重复通知 |
| Webhook Secret 与 API Secret 分开管理 | 最小权限原则 |