配置钉钉机器人加签密钥的核心是使用 HMAC-SHA256 算法对时间戳和密钥进行签名,并将结果作为参数附加到 webhook 地址中。该方案适合服务端主动推送消息场景,风险边界在于时间戳格式错误或密钥复制不完整会导致请求被返回 401 状态码拦截。
先说结论:开启加签后,必须在请求 URL 中携带正确计算的时间戳和签名参数,否则钉钉网关会直接拒绝请求。
- 先判断:确认机器人安全设置已选择“加签”模式并复制完整密钥。
- 优先做:使用 HMAC-SHA256 算法计算签名并对结果进行 URL 编码。
- 再验证:发送测试请求确认 HTTP 状态码为 200 且机器人收到消息。
命令速用版
以下 Python 代码片段可直接用于生成签名参数,适用于大多数服务端语言逻辑参考。
import hmac
import hashlib
import base64
import urllib.parse
import time
secret = 'SECxxxxxxxxxx' # 替换为机器人设置的密钥
timestamp = str(round(time.time() * 1000))
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}")为什么会这样
钉钉网关通过校验签名和时间戳来确认请求来源的合法性和时效性。加签机制防止了 webhook 地址泄露后被第三方恶意调用发送垃圾消息,同时时间戳限制了请求的有效窗口,避免重放攻击。
分步处理
按照以下顺序完成配置和代码修改,每一步完成后检查对应状态。
步骤 1:获取密钥
在钉钉机器人管理页面,安全设置栏选择“加签”,复制显示的密钥。密钥通常以 SEC 开头,复制时注意不要包含多余空格或换行。
步骤 2:生成时间戳
代码中获取当前时间毫秒级时间戳。必须使用毫秒值(13 位整数),不能使用秒值或字符串格式时间。
步骤 3:计算签名
将时间戳和密钥用换行符连接,使用 HMAC-SHA256 算法计算哈希值,再进行 Base64 编码和 URL 编码。顺序不可颠倒,编码方式必须一致。
步骤 4:拼接 URL
将原始 webhook 地址后追加参数,格式为×tamp=xxx&sign=xxx。注意第一个参数前用?,后续参数用&,如果原始 URL 已含参数则全部用&。
步骤 5:发送请求
使用 HTTP POST 方法发送 JSON 数据。请求头 Content-Type 必须设置为application/json。
怎么验证是否生效
发送请求后检查 HTTP 响应状态码。如果配置正确,钉钉接口返回状态码 200 且 body 中包含"errcode":0。如果返回 401 或 errcode 非 0,通常表示签名计算错误或时间戳偏差过大。同时在钉钉群内观察是否实际收到测试消息,避免接口返回成功但消息被群设置拦截。
常见坑
- 密钥复制错误:SEC 密钥前后容易混入不可见字符,建议在代码中打印密钥长度核对。
- 时间戳单位错误:必须使用毫秒级时间戳,使用秒级会导致签名校验失败。
- URL 编码遗漏:签名结果包含特殊字符,必须进行 URL 编码后再拼接到 URL 中。
- 换行符差异:字符串拼接时时间戳和密钥之间必须是标准换行符
\n,Windows 环境下注意不要变成\r\n。
常见问题
请求返回 401 状态码怎么办
401 表示签名校验失败,重点检查时间戳是否为毫秒值、密钥是否完整复制、签名算法是否为 HMAC-SHA256。
密钥泄露后是否可以更换
可以在钉钉机器人设置页面重新生成密钥,更换后所有旧代码中的密钥需同步更新,否则旧请求会被拦截。
支持 HTTP GET 请求吗
钉钉自定义机器人 webhook 仅支持 HTTP POST 请求,使用 GET 方法会直接返回错误。
参考来源
- 钉钉开放平台,自定义机器人接入,https://open.dingtalk.com/document/robots/custom-robot-access