Skip to content

İmza doğrulama

Stoneity webhook'ları Standard Webhooks şemasıyla imzalar.

  1. İmzalanan içeriği kurun: "{webhook-id}.{webhook-timestamp}.{ham gövde}".
  2. Secret'ın ham baytlarıyla HMAC-SHA256 hesaplayın: secret whsec_ + base64'tür; whsec_ sonrasını base64 çözün.
  3. Özeti base64'e çevirip webhook-signature başlığındaki v1, 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.
  4. 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.

Stoneity Public API v1