Verify the HMAC signature with a constant-time comparison, plus a timestamp (replay protection).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // ====================================================================== // Q: Webhook from the logistics provider: what do you check? // // Verify the HMAC signature with a constant-time comparison, plus a timestamp // (replay protection). Dedupe by event id. Reply quickly with 202 and process // asynchronously. // ====================================================================== app.MapPost("/webhooks/shipping", async (HttpRequest req, IOptions<WebhookOptions> opt, ...) => { using var reader = new StreamReader(req.Body); var body = await reader.ReadToEndAsync(); var signature = req.Headers["X-Signature"].ToString(); var expected = Convert.ToHexString( HMACSHA256.HashData(Encoding.UTF8.GetBytes(opt.Value.Secret), Encoding.UTF8.GetBytes(body))); if (!CryptographicOperations.FixedTimeEquals( Encoding.UTF8.GetBytes(expected), Encoding.UTF8.GetBytes(signature.ToUpperInvariant()))) return Results.Unauthorized(); // dedupe by event id, write to a queue, fast 202 return Results.Accepted(); }); |