Webhook 验证
本文概述了如何进行 webhook 验证。
检查签名
TikTok webhook 随签名一起发送,目标服务器可使用此签名验证相关事件来自 TikTok 而非第三方或恶意系统。
强烈建议 webhook 用户在处理各个 webhook 事件前先验证这些签名。
验证信息签名
为保护您的应用程序免受中间人攻击和重放攻击,请验证发送至您应用的信息签名。Webhook 发送时间戳和 webhook 请求正文都是已签名的有效负载的一部分,因此,如果攻击者无法使签名失效,就不能更改时间戳。如果签名有效但时间戳过期,那么可以让您的应用程序拒绝有效负载。
签名作为 TikTok-Signature的header包含在 webhook 请求中。
TikTok-Signature 示例
(code curl http)
"Tiktok-Signature": "t=1633174587,s=18494715036ac4416a1d0a673871a2edbcfc94d94bd88ccd2c5ec9b3425afe66"
(/code)
签名验证
步骤 1:从header提取时间戳和签名
用,字符作分隔符拆分Tiktok-Signature 的header,获取元素列表。然后用=字符作分隔符拆分每个元素,获取键值对。
t 键的值对应以秒为单位的 Unix 时间戳,s 键对应在发送 webhook 时 TikTok 平台生成的签名。
步骤 2:生成签名
要生成签名并与已收到的签名进行对比的信息,可通过连接以下内容创建:
- 已接收的时间戳字符串
- '.'字符
- 转换成JSON 字符串的请求body
创建完成后,将( API for Business 开发者门户网站为应用配置的)应用密钥作为键,使用 SHA256 散列函数计算 HMAC(基于散列的消息身份验证代码)。然后对已生成的 HMAC 进行十六进制编码,以便与已收到的签名进行对比。
步骤 3:签名对比
将header中的签名与已生成的签名进行对比。如果二者匹配,计算当前以秒为单位的 Unix 时间戳与header中已收到的时间戳之间的差值,以此确定差异是否在您的容差范围内。
运行示例
Node
(code curl http)
var CryptoJS = require("crypto-js");
// Example serialized copy of the webhook request to verify
const webhookRequest = {
headers: {
"host": "enj1gzfy7ltvrqf.m.pipedream.net",
"x-amzn-trace-id": "Root=1-61de8b6a-1c7695005636528b40cac95f",
"content-length": "251",
"user-agent": "tiktok-webhook",
"content-type": "application/json;charset=UTF-8",
"tiktok-signature": "t=1641974633,s=dc023ece112b3a07d809896fd929928a132168d95d2a2e43aab0105fbb291df8",
"webhook-schema-version": "v1.0",
"x-tt-logid": "202201120803530102451591650189C78",
"x-envoy-return-response-flags": "1",
"rpc-persist-ori-path": "/"
},
body: {
client_key: "7043848340043202562",
event: "share.video.publish_complete",
create_time: 1641974632,
user_openid: "a81e31c6-3b57-40d7-9253-c2f211e70514",
content: "{\"share_id\":\"v_publish.7052073813521844225\",\"video_id\":\"7044071604573310209\"}"
}
};
// Replace your signing key (app secret) and acceptable webhook delay in seconds
const signingKey = "****************************************";
const acceptableDelay = 5;
// Collect the necessary information for webhook validation
const body = JSON.stringify(webhookRequest.body);
const keys = webhookRequest.headers["tiktok-signature"].split(',');
const receivedTimestamp = keys[0].split("=")[1];
const receivedSignature = keys[1].split("=")[1];
// Function to validate incoming webhook signature
function validateSignature (receivedTimestamp, receivedSignature, body) {
// Create signed payload, generate HMAC, hex encode the HMAC
const signedPayload = receivedTimestamp + '.' + body;
const hmac = CryptoJS.HmacSHA256(signedPayload, signingKey);
const computedSignature = CryptoJS.enc.Hex.stringify(hmac);
// If computed and received signatures match
if (computedSignature === receivedSignature) {
// Check if current timestamp within acceptable delay from received timestamp
const currentTimestamp = Math.round(new Date().getTime() / 1000);
const delay = currentTimestamp - receivedTimestamp;
if (delay <= acceptableDelay) return true;
else return false;
}
else return false;
};
if (validateSignature(receivedTimestamp, receivedSignature, body)) {
// return a 200 HTTP response and continue with webhook processing
}
else {
// return a 4xx HTTP response status and raise a verification exception
// log the x-tt-logid header
}
(/code)