发送钉钉机器人消息出现 timestamp 验证失败错误怎么修

文章导读
解决这个问题的核心是确保客户端系统时间准确,并且签名计算使用的 timestamp 与请求 URL 中携带的完全一致。
📋 目录
  1. A 命令速用版
  2. B 完整请求代码示例
  3. C 为什么会这样
  4. D 分步处理
  5. E 怎么验证是否生效
  6. F 常见坑
  7. G 参考来源
A A

解决这个问题的核心是确保客户端系统时间准确,并且签名计算使用的 timestamp 与请求 URL 中携带的完全一致。

先说结论:大多数情况下是因为服务器时间不同步或签名算法实现有误,需优先校准时间并核对代码逻辑。

  • 先确认:服务器系统时间是否与网络时间同步
  • 先处理:重新生成签名,确保 timestamp 和 sign 对应
  • 再验证:发送测试消息观察钉钉后台响应

命令速用版

如果你需要快速生成正确的签名参数,可以使用以下 Python 代码片段进行测试:

import time
import hmac
import hashlib
import urllib.parse
import base64

secret = '你的密钥'
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}&sign={sign}")

注意:实际请求时请将上述参数拼接到 webhook 地址后。

完整请求代码示例

以下是包含签名计算与消息发送的完整 Python 示例,可直接替换测试:

发送钉钉机器人消息出现 timestamp 验证失败错误怎么修
import time
import hmac
import hashlib
import base64
import urllib.parse
import requests
import json

webhook = 'https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN'
secret = 'YOUR_SECRET'

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))

url = f'{webhook}×tamp={timestamp}&sign={sign}'
data = {
    "msgtype": "text",
    "text": {
        "content": "测试消息:timestamp 验证修复验证"
    }
}
response = requests.post(url, json=data)
print(response.status_code)
print(response.json())

为什么会这样

钉钉自定义机器人开启了“加签”安全设置后,请求必须携带 timestamp 和 sign 参数。服务端会校验这两个参数:

  1. 时间有效性:timestamp 必须是当前时间毫秒戳,且与服务端时间差不能过大(通常允许一定误差,但过大则失效)。
  2. 签名一致性:sign 是使用 HMAC-SHA256 算法,基于 timestamp 和 secret 计算得出的。如果代码里用的 timestamp 和 URL 里传的不一样,签名就会对不上。

公开资料中没有看到可靠的量化数据说明具体的时间容忍窗口,建议保持秒级同步。

分步处理

第一步:检查服务器时间

在 Linux 服务器上执行 date 命令,对比当前时间与标准时间。如果偏差超过几分钟,建议使用 timedatectl 或 chrony 同步时间。例如执行 sudo timedatectl set-ntp true 开启自动同步,或 sudo systemctl restart chronyd 重启服务。

第二步:核对签名代码

发送钉钉机器人消息出现 timestamp 验证失败错误怎么修

检查代码中生成 sign 的逻辑。确保字符串拼接格式是 timestamp + "\n" + secret。注意换行符是必需的,不能遗漏。

第三步:检查 URL 编码

生成的 sign 字符串包含特殊字符,必须经过 URL 编码(urlencode)后再拼接到请求地址中,否则传输过程中字符可能变质。

怎么验证是否生效

发送请求后,检查 HTTP 响应状态码是否为 200,且响应 body 中 errcode 为 0。如果群内收到消息且后台记录状态为成功,即表示修复成功。也可以在钉钉机器人管理后台查看“最近发送记录”,确认状态为成功。

常见坑

  • 密钥复制多了空格:secret 前后不能包含空格或换行,建议打印长度核对。
  • 时间单位错误:钉钉要求毫秒级时间戳,部分语言默认是秒级,需要乘以 1000。
  • 重复使用旧时间戳:每次请求都应生成新的 timestamp,不要缓存旧的签名参数。

参考来源

  • 钉钉开放平台 - 自定义机器人接入,URL: https://open.dingtalk.com/document/robots/custom-robot-access