钉钉机器人 webhook 请求的 timestamp 和 sign 签名需通过 HMAC-SHA256 算法计算,将当前时间戳与加签密钥组合后加密并 Base64 编码。该机制适用于开启了“加签”安全设置的自定义机器人,主要风险在于时间戳过期导致请求失效。
先说结论:计算签名必须使用官方提供的 secret 和当前毫秒级时间戳,缺一不可。
- 适合:开启了“加签”安全设置的钉钉自定义机器人 webhook 请求。
- 先看:确认机器人管理后台已生成 secret 密钥,并记录保存。
- 建议:代码中实现自动获取时间戳和签名逻辑,避免手动填写导致过期。
命令速用版
以下 Python 代码片段可直接用于生成签名,替换 secret 后即可使用。
import time
import hmac
import hashlib
import base64
import urllib.parse
timestamp = str(round(time.time() * 1000))
secret = 'SECxxxxxxxxxx' # 替换为实际 secret
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(f"timestamp: {timestamp}")
print(f"sign: {sign}")为什么会这样
签名机制的核心目的是防止请求被篡改和重放攻击。钉钉服务器通过验证时间戳确保请求是近期发出的,通过验证签名确保请求携带了正确的密钥。公开资料中没有看到可靠的量化数据说明具体防御了多少攻击,但这是 API 安全通信的标准做法。
分步处理
按顺序执行以下步骤可完成签名配置与请求发送。
步骤 1:获取密钥
进入钉钉机器人管理后台,安全设置中选择“加签”,复制显示的 secret 密钥。该密钥只显示一次,丢失需重新生成。
步骤 2:生成时间戳
获取当前时间戳,单位必须是毫秒(13 位整数)。Python 中使用round(time.time() * 1000),Java 中使用System.currentTimeMillis()。
步骤 3:计算签名
将时间戳字符串、换行符\n、密钥字符串拼接。使用 HMAC-SHA256 算法,密钥为 secret,消息为拼接字符串。结果进行 Base64 编码,再进行 URL Encode。
步骤 4:发送请求
将timestamp和sign作为查询参数附加到 webhook URL 后。请求方法为 POST,Content-Type 为 application/json。
怎么验证是否生效
发送请求后检查钉钉返回的 JSON 响应。若errcode为0且errmsg为ok,表示签名验证通过。若返回invalid sign或timestamp invalid,需检查时间戳单位或签名算法细节。
常见坑
- 时间戳单位错误:必须使用毫秒,使用秒会导致验证失败。
- 换行符遗漏:拼接字符串时时间戳和 secret 之间必须包含
\n,不能省略。 - 编码问题:Base64 编码后必须进行 URL Encode,否则特殊字符会导致请求解析错误。
- 密钥泄露:secret 密钥等同于密码,不应提交到公共代码仓库。
常见问题
时间戳有效期是多久?
公开资料中未明确具体有效期分钟数,但建议请求发出时间与服务器接收时间差控制在 1 小时内,超时会导致timestamp invalid错误。
secret 密钥可以重置吗?
可以重置,但重置后旧密钥立即失效,所有使用该密钥的服务需同步更新配置,否则无法发送消息。
签名计算支持哪些编程语言?
支持所有标准 HMAC-SHA256 库的语言,如 Python、Java、Go、Node.js 等,算法逻辑一致,仅函数调用方式不同。
参考来源
- 钉钉开放平台 - 自定义机器人:https://open.dingtalk.com/document/robots/custom-robot-access