İmza doğrulama
Stoneity webhook'ları Standard Webhooks şemasıyla imzalar.
- İmzalanan içeriği kurun:
"{webhook-id}.{webhook-timestamp}.{ham gövde}". - Secret'ın ham baytlarıyla
HMAC-SHA256hesaplayın: secretwhsec_+ base64'tür;whsec_sonrasını base64 çözün. - Özeti base64'e çevirip
webhook-signaturebaşlığındakiv1,sonrası değerle sabit zamanlı karşılaştırın. Secret yenileme sırasında başlıkta boşlukla ayrılmış birden çok imza olabilir; herhangi biri eşleşirse geçerlidir. - 5 dakikadan eski zaman damgalarını reddedin (tekrar oynatma koruması).
js
import crypto from 'node:crypto';
export function verify(secret, headers, rawBody) {
const id = headers['webhook-id'];
const ts = headers['webhook-timestamp'];
const signatures = (headers['webhook-signature'] || '').split(' ');
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64');
const expected = 'v1,' + crypto.createHmac('sha256', key).update(`${id}.${ts}.${rawBody}`).digest('base64');
return signatures.some((s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}csharp
using System.Security.Cryptography;
using System.Text;
static bool Verify(string secret, string id, string ts, string body, string signatureHeader)
{
if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - long.Parse(ts)) > 300) return false;
var key = Convert.FromBase64String(secret.Replace("whsec_", ""));
using var hmac = new HMACSHA256(key);
var expected = "v1," + Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes($"{id}.{ts}.{body}")));
return signatureHeader.Split(' ').Any(s =>
s.Length == expected.Length && CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(s), Encoding.UTF8.GetBytes(expected)));
}python
import base64, hmac, hashlib, time
def verify(secret: str, headers: dict, raw_body: bytes) -> bool:
msg_id, ts = headers["webhook-id"], headers["webhook-timestamp"]
if abs(time.time() - int(ts)) > 300:
return False
key = base64.b64decode(secret.removeprefix("whsec_"))
digest = hmac.new(key, f"{msg_id}.{ts}.".encode() + raw_body, hashlib.sha256).digest()
expected = "v1," + base64.b64encode(digest).decode()
return any(hmac.compare_digest(s, expected) for s in headers["webhook-signature"].split(" "))Doğrulamayı her zaman JSON ayrıştırmadan önce, ham istek gövdesi üzerinde yapın.