Webhook 簽名驗證
Webhook 簽名驗證
發送端實際協議
| Header | 內容 |
|---|---|
X-Webhook-Signature | HMAC-SHA256的64位小寫十六進制摘要,無前綴 |
X-Webhook-Event | 事件名稱,未被簽名覆蓋 |
Content-Type | application/json |
原始 signing_secret 是註冊/輪換時一次返回的明文。實際key派生為 UTF8(SHA256(secret).hex_lowercase),簽名消息是未經解析的原始HTTP body字節。官方SDK helper封裝該派生與定時無關比較;不要將服務端存儲hash作為原始secret傳入。
簽名驗證body真實性與完整性。當前協議沒有簽名時間戳或投遞ID,不提供防重放或事件header認證。不要依賴未經簽名的header做授權決定;業務去重需要你自己的可信標識與存儲,不能假設每個payload包含統一event ID。
使用正式SDK校驗
下面是可獨立運行的驗籤程序。為復現原始字節,將接收到的body原樣base64存入 APPFORGES_WEBHOOK_BODY_BASE64,signature來自 X-Webhook-Signature,secret來自安全配置。真實HTTP handler也應先獲取raw body、校驗成功後才JSON解析;生產不要日誌記錄secret或完整body。
安裝見快速開始。示例輸出true/false,只展示驗籤,不處理業務事件。
TypeScript
import { verifyWebhookSignature } from "@appforges/sdk/runtime/webhook";
const body = new Uint8Array(Buffer.from(process.env.APPFORGES_WEBHOOK_BODY_BASE64!, "base64"));
const valid = await verifyWebhookSignature(
body,
process.env.APPFORGES_WEBHOOK_SIGNATURE!,
[process.env.APPFORGES_WEBHOOK_SECRET!],
);
console.log(valid);Python
import base64
import os
from appforges import verify_webhook_signature
body = base64.b64decode(os.environ["APPFORGES_WEBHOOK_BODY_BASE64"], validate=True)
valid = verify_webhook_signature(
body,
os.environ["APPFORGES_WEBHOOK_SIGNATURE"],
[os.environ["APPFORGES_WEBHOOK_SECRET"]],
)
print(valid)Go
package main
import (
"encoding/base64"
"fmt"
"log"
"os"
"github.com/appforges/appforges-sdk-go/runtime"
)
func main() {
body, err := base64.StdEncoding.DecodeString(os.Getenv("APPFORGES_WEBHOOK_BODY_BASE64"))
if err != nil { log.Fatal(err) }
valid := runtime.VerifyWebhookSignature(body,
os.Getenv("APPFORGES_WEBHOOK_SIGNATURE"),
[]string{os.Getenv("APPFORGES_WEBHOOK_SECRET")})
fmt.Println(valid)
}輪換與錯誤處理
輪換立即替換髮送端密鑰,沒有24小時雙籤保證。消費者可短期配置多個原始secret,兼容在途舊請求;完成遷移後移除舊secret。錯誤key、空key、body篡改和畸形signature應失敗。校驗失敗時停止業務處理,按你的HTTP接收契約返回錯誤。