跳到內容

Inbound Webhook 簽章

每次 inbound POST 都必須帶 X-TimestampX-NonceX-Signature。timestamp 使用 Unix seconds,與伺服器時間的差距不可超過正負 300 秒。nonce 必須是 1 到 128 個可見、無空白的 ASCII 字元,建議使用 UUID;同一 webhook 的 nonce 會保留 600 秒,重複使用會被拒絕。

使用只顯示一次的 signing secret,針對下列「完全相同的原始 bytes」計算小寫十六進位 HMAC-SHA256:

timestamp + ":" + nonce + ":" + raw_request_body

簽完後不可再 parse 並重新序列化 JSON;空白或 key 順序改變都會讓簽章失效。

Curl:

Terminal window
TS=$(date +%s); NONCE=$(uuidgen); BODY='{"event":"example"}'
SIG=$(printf '%s:%s:%s' "$TS" "$NONCE" "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -hex | awk '{print $2}')
curl -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -H "X-Timestamp: $TS" -H "X-Nonce: $NONCE" -H "X-Signature: $SIG" -d "$BODY"

Node:

const body = JSON.stringify({ event: "example" });
const ts = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomUUID();
const signature = crypto.createHmac("sha256", secret).update(`${ts}:${nonce}:${body}`).digest("hex");

Python:

body = b'{"event":"example"}'
signed = timestamp.encode() + b":" + nonce.encode() + b":" + body
signature = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()

arinova.webhook.create_webhook, arinova.webhook.get_webhook

Also known as

webhook 簽章, HMAC, X-Signature, X-Timestamp, X-Nonce, 發送端整合


Machine-readable Markdown · Knowledge index

Build a7f47a5ca54ddcf7806cd48b81ce1b9827042766