跳转到主要内容
为确保回调请求的安全性,强烈建议在生产环境中启用 Webhook HMAC 签名校验,防止伪造请求和重放攻击。

算法说明

Kie AI 使用 HMAC-SHA256 算法生成签名,用于验证 Webhook 回调的完整性和真实性。 签名生成步骤:
  1. 拼接待签名字符串taskId + "." + timestampSeconds
    • taskId:从请求体中获取的任务ID
    • timestampSeconds:从 X-Webhook-Timestamp 请求头获取的Unix时间戳(秒级)
  2. 使用 HMAC-SHA256 计算签名
    signature = HMAC-SHA256(dataToSign, webhookHmacKey)
    
  3. Base64 编码
    finalSignature = Base64.encode(signature)
    

获取 Webhook HMAC Key

您可以在 Kie AI 设置页面 生成并查看您的 webhookHmacKey
webhookHmacKey 用于验证回调请求是否来自 Kie AI 官方服务器。请妥善保管此密钥,切勿泄露或提交到代码仓库。

Webhook Header 说明

当您在设置页面启用 webhookHmacKey 功能后,所有回调请求的 HTTP Header 中将包含以下字段:
X-Webhook-Timestamp
integer
必填
回调请求发送时的 Unix 时间戳(秒)。
X-Webhook-Signature
string
必填
使用 HMAC-SHA256 算法生成的签名,采用 Base64 编码。签名生成规则:
base64(HMAC-SHA256(taskId + "." + timestamp, webhookHmacKey))
其中:
  • taskId 为回调 body 中的任务 ID
  • timestampX-Webhook-Timestamp 的值
  • webhookHmacKey 为您在控制台生成的密钥

Webhook 校验流程

请按照以下步骤验证 Webhook 请求的合法性:
1

读取 Header 字段

从 HTTP Header 中提取 X-Webhook-TimestampX-Webhook-Signature 两个字段。
const timestamp = req.headers['X-Webhook-Timestamp'];
const receivedSignature = req.headers['X-Webhook-Signature'];
2

生成签名

使用本地保存的 webhookHmacKey,按照以下规则生成 HMAC-SHA256 签名:
  1. 从请求 body 中提取 task_id
  2. 拼接字符串:taskId + "." + timestamp
  3. 使用 HMAC-SHA256 算法和 webhookHmacKey 生成签名
  4. 对签名结果进行 Base64 编码
const crypto = require('crypto');

const taskId = req.body.data.task_id;
const message = `${taskId}.${timestamp}`;

const computedSignature = crypto
  .createHmac('sha256', webhookHmacKey)
  .update(message)
  .digest('base64');
3

对比签名

将计算出的签名与 X-Webhook-Signature 进行对比。使用常量时间比较算法防止时序攻击。
// 使用 crypto.timingSafeEqual 进行常量时间比较
if (computedSignature.length !== receivedSignature.length) {
  return res.status(401).json({ error: 'Invalid signature' });
}

const isValid = crypto.timingSafeEqual(
  Buffer.from(computedSignature),
  Buffer.from(receivedSignature)
);

if (isValid) {
  // 签名验证通过,请求合法
  console.log('Webhook signature verified');
} else {
  // 签名验证失败,拒绝请求
  return res.status(401).json({ error: 'Invalid signature' });
}
如果签名一致,则确认该 Webhook 请求来自 Kie AI 官方服务器,可以安全处理。

完整示例代码

以下是在常用编程语言中实现 Webhook 签名校验的完整示例:
const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

// 从环境变量或配置中读取 webhookHmacKey
const WEBHOOK_HMAC_KEY = process.env.WEBHOOK_HMAC_KEY;

function generateSignature(taskId, timestampSeconds, secret) {
  // 1. 拼接待签名字符串
  const dataToSign = `${taskId}.${timestampSeconds}`;
  
  // 2. 使用 HMAC-SHA256 计算签名
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(dataToSign);
  
  // 3. Base64 编码
  return hmac.digest('base64');
}

function verifySignature(taskId, timestampSeconds, receivedSignature, secret) {
  // 重新生成签名
  const expectedSignature = generateSignature(taskId, timestampSeconds, secret);
  
  // 使用安全的字符串比较
  if (expectedSignature.length !== receivedSignature.length) {
    return false;
  }
  
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature),
    Buffer.from(receivedSignature)
  );
}

function verifyWebhookSignature(req, res, next) {
  // 1. 读取 Header 字段
  const timestamp = req.headers['x-webhook-timestamp'];
  const receivedSignature = req.headers['x-webhook-signature'];

  if (!timestamp || !receivedSignature) {
    return res.status(401).json({ error: 'Missing signature headers' });
  }

  // 2. 验证签名
  const taskId = req.body.data?.task_id;
  if (!taskId) {
    return res.status(400).json({ error: 'Missing task_id' });
  }

  const isValid = verifySignature(taskId, timestamp, receivedSignature, WEBHOOK_HMAC_KEY);
  
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // 签名验证通过
  next();
}

// 应用中间件
app.post('/webhook-callback', verifyWebhookSignature, (req, res) => {
  const { code, msg, data } = req.body;
  
  console.log('收到合法的 Webhook 请求:', {
    taskId: data.task_id,
    status: code,
    callbackType: data.callbackType
  });
  
  // 处理回调数据...
  
  res.status(200).json({ status: 'received' });
});

app.listen(3000, () => {
  console.log('Webhook 服务器运行在端口 3000');
});

示例 Webhook 请求

以下是一个完整的 webhook 请求示例:
POST /your-webhook-endpoint HTTP/1.1
Host: your-server.com
Content-Type: application/json
X-Webhook-Timestamp: 1769670760
X-Webhook-Signature: KxDlpbbq0GDOKqm0+FuJpJWTzY8baHSjhEt4kwElqQI=

{
  "taskId": "ee9c2715375b7837f8bb51d641ff5863",
  "code": 200,
  "msg": "Success",
  "data": {
    "task_id": "ee9c2715375b7837f8bb51d641ff5863",
    "callbackType": "task_completed",
    ...
  }
}