Secure Webhook Signature Verification
Owner: SnippetBot
Created: 2026-07-21 00:00:21
Size: 2.23 KB
Expires: Never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
/**
* Verifies the signature of an incoming webhook payload.
* This prevents tampering and ensures the request came from a trusted source.
*
* @param string $payload The raw JSON payload from the webhook body.
* @param string $signatureHeader The value of the signature header (e.g., 'X-Webhook-Signature').
* @param string $secret The shared secret key provided by the API.
* @param string $algo The hashing algorithm used (e.g., 'sha256').
* @return bool True if the signature is valid, false otherwise.
*/
function verifyWebhookSignature(string $payload, string $signatureHeader, string $secret, string $algo = 'sha256'): bool
{
// Extract the signature from the header. Assumes format like 't=TIMESTAMP,v=SIGNATURE' or just 'SIGNATURE'
// Adjust this parsing based on the specific API's signature header format.
// For simplicity, we assume the header *is* the signature directly or we can parse it.
// Example: For 'sha256=...' format, you'd parse it.
$parts = explode('=', $signatureHeader, 2);
$receivedSignature = (count($parts) === 2) ? $parts[1] : $signatureHeader;
// Calculate the expected signature
$expectedSignature = hash_hmac($algo, $payload, $secret, false); // raw_output=false for hex string
// Use hash_equals to prevent timing attacks
return hash_equals($expectedSignature, $receivedSignature);
}
// Example Usage:
// $secretKey = 'your_super_secret_webhook_key'; // Get this from environment variables or secure config
// $rawPayload = file_get_contents('php://input');
// $signatureHeader = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? ''; // Adjust header name as needed
// if (empty($rawPayload) || empty($signatureHeader)) {
// http_response_code(400); // Bad Request
// die('Missing payload or signature.');
// }
// if (verifyWebhookSignature($rawPayload, $signatureHeader, $secretKey)) {
// // Signature is valid, process the webhook payload
// $eventData = json_decode($rawPayload, true);
// // ... your logic to handle the eventData ...
// http_response_code(200); // OK
// echo 'Webhook received and processed.';
// } else {
// // Signature is invalid, reject the request
// http_response_code(403); // Forbidden
// die('Invalid webhook signature.');
// }