How to fix Insecure Webhooks
in .NET 8 Web API
Executive Summary
Webhooks are essentially reverse APIs. If you are blindly accepting POST requests without verifying the source, you are inviting attackers to perform unauthorized actions or inject malicious data. In .NET 8, a common mistake is trusting the payload based solely on the endpoint's existence. A secure implementation requires HMAC-SHA256 signature verification to ensure the request originated from a trusted provider and wasn't tampered with in transit.
The Vulnerable Pattern
[HttpPost("api/webhooks/receive")]
public IActionResult ReceiveWebhook([FromBody] dynamic payload)
{
// VULNERABILITY: No signature verification.
// Anyone can POST any JSON to this endpoint.
_logger.LogInformation("Processing payload: {Payload}", payload);
return Ok();
}
The Secure Implementation
The secure implementation enforces three critical layers: 1. Shared Secret: Only the sender and receiver know the key used to sign the payload. 2. HMAC Verification: We re-calculate the HMAC-SHA256 hash of the raw request body and compare it to the provider's header. 3. Constant-Time Comparison: Using CryptographicOperations.FixedTimeEquals prevents side-channel timing attacks that could allow an attacker to brute-force the signature byte-by-byte. Always read the raw body for hash calculation before deserialization to ensure data integrity.
[HttpPost("api/webhooks/receive")] public async TaskReceiveWebhook() { var secret = _configuration["WebhookSettings:Secret"]; if (!Request.Headers.TryGetValue("X-Hub-Signature-256", out var signature)) return Unauthorized("Missing signature."); using var reader = new StreamReader(Request.Body); var body = await reader.ReadToEndAsync(); var keyBytes = Encoding.UTF8.GetBytes(secret); var bodyBytes = Encoding.UTF8.GetBytes(body); using var hmac = new HMACSHA256(keyBytes); var hashBytes = hmac.ComputeHash(bodyBytes); var expectedSignature = "sha256=" + Convert.ToHexString(hashBytes).ToLower(); // Use FixedTimeEquals to prevent timing attacks if (!CryptographicOperations.FixedTimeEquals( Encoding.UTF8.GetBytes(expectedSignature), Encoding.UTF8.GetBytes(signature))) { return Unauthorized("Invalid signature."); } var payload = JsonSerializer.Deserialize<WebhookDto>(body); return Ok();
}
Your .NET 8 Web API API
might be exposed to Insecure Webhooks
74% of .NET 8 Web API apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.