Webhook Signature Verification
To verify the the authenticity that your scheduled webhook was triggered by cronhooks you can check the signature.
- - ASP.NET / C#
- - PHP
- - Typescript / Node
ASP.NET / C#
[Route("api/[controller]")]
public class CronhooksFailureWebHook : Controller
{
// You can find your endpoint's secret in your API Keys settings
const string secret = "wh_...";
[HttpPost]
public void Index()
{
var json = new StreamReader(HttpContext.Request.Body).ReadToEnd();
var computedSignature = ComputeSignature(secret, json);
var cronhooksSignature = Request.Headers["Cronhooks-Signature"];
if (SecureCompare(computedSignature, cronhooksSignature))
{
// Verified
}
}
private string ComputeSignature(string secret, string payload)
{
var secretBytes = Encoding.UTF8.GetBytes(secret);
var payloadBytes = Encoding.UTF8.GetBytes(payload);
using (var cryptographer = new HMACSHA256(secretBytes))
{
var hash = cryptographer.ComputeHash(payloadBytes);
return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant();
}
}
private bool SecureCompare(string a, string b)
{
if (a.Length != b.Length)
{
return false;
}
var result = 0;
for (var i = 0; i < a.Length; i++)
{
result |= a[i] ^ b[i];
}
return result == 0;
}
}
PHP
$webhook_secret = 'wh_...';
$payload = @file_get_contents('php://input');
$cronhooks_sig_header = $_SERVER['HTTP_CRONHOOKS_SIGNATURE'];
$signature = computeSignature($payload, $webhook_secret);
if(secureCompare($cronhooks_sig_header, $signature)){
// Verified
}
private function computeSignature($payload, $secret){
return hash_hmac("sha256", $payload, $secret);
}
private function secureCompare($secret, $computed){
if(function_exists('hash_equals')){
return hash_equals($secret, $computed);
}
if (strlen($secret) != strlen($computed)) {
return false;
}
$result = 0;
for ($i = 0; $i < strlen($secret); $i++) {
$result |= ord($secret[$i]) ^ ord($computed[$i]);
}
return ($result == 0);
}
Typescript / Node
import crypto from 'crypto'
const cronhooksSignature = req.headers['cronhooks-signature']; // req.headers['Cronhooks-Signature']
let body = rawBody.toString();
const expectedSignature = crypto
.createHmac('sha256', process.env.CRONHOOKS_SECRET)
.update(body)
.digest('hex');
let isValidRequest = (cronhooksSignature !== expectedSignature);