一旦发现钉钉机器人 webhook 地址泄露,最稳妥的做法是立即停用旧机器人并创建新地址,同时在新机器人上启用 IP 白名单和加签机制,从源头限制调用权限。
先说结论:Webhook 泄露主要导致群消息被滥用,无法直接读取群历史,但需立刻轮换地址并加固配置。
- 先判断:确认泄露范围,评估是否已有异常消息发送。
- 优先做:删除旧机器人,新建机器人并配置 IP 白名单与加签。
- 再验证:从受信任服务器发送测试消息,确认非白名单 IP 被拦截。
快速处理思路
由于 webhook 安全配置主要在钉钉管理后台完成,不涉及服务器命令行操作,请按以下逻辑快速响应:
- 登录钉钉管理后台,找到对应群机器人,直接删除或停用。
- 重新添加自定义机器人,获取新的 webhook 地址。
- 在安全设置中,勾选"IP 白名单"并填入服务器出口 IP。
- 勾选"加签",获取 Secret,更新代码中的签名算法。
为什么会这样
钉钉自定义机器人的 webhook 地址本质上是一个公开的 HTTP POST 接口。一旦泄露,任何知道该地址的人都可以向群里发送消息。虽然机器人权限通常仅限于发送,无法读取群聊天记录或获取用户隐私,但攻击者可以利用它发送钓鱼链接、垃圾广告或虚假信息,干扰正常沟通。
启用 IP 白名单后,钉钉服务器会校验请求来源 IP,非白名单内的请求直接拒绝。加签机制则要求请求携带特定签名,防止请求被篡改或重放。两者结合能大幅降低地址泄露后的可利用性。
分步处理
第一步:止损
立即进入钉钉群设置 - 智能群助手,找到泄露的机器人,点击移除。这一步能让旧 webhook 立即失效。
第二步:重建与加固
重新添加自定义机器人。在安全设置环节,务必同时开启以下两项:
- IP 白名单:填入你业务服务器的出口公网 IP。如果是云服务器,注意 NAT 网关或弹性公网 IP 的地址。
- 加签:复制生成的 Secret,用于后续请求签名计算。
第三步:代码更新
修改业务代码,将新 webhook 地址和 Secret 配置进去。签名计算需要将时间戳和 Secret 进行 HMAC-SHA256 运算、Base64 编码后再 URL Encode。以下是主流语言的实现示例:
Python 示例:
import hmac
import hashlib
import base64
import urllib.parse
import time
secret = 'SECxxxxxxxx'
timestamp = str(round(time.time() * 1000))
string_to_sign = '{}\n{}'.format(timestamp, secret)
hmac_code = hmac.new(secret.encode('utf-8'), string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
Java 示例:
String secret = "SECxxxxxxxx";
Long timestamp = System.currentTimeMillis();
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
怎么验证是否生效
1. 正向测试:在配置了白名单的服务器上触发告警,确认群里能收到消息。
2. 反向测试:尝试在未在白名单内的机器上(或使用本地电脑)直接 curl 该 webhook 地址,钉钉接口应返回错误码,且群里无消息。
3. 接口调用验证命令:使用以下 curl 命令模拟带签名的请求,确保参数格式正确:
curl "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN×tamp=YOUR_TIMESTAMP&sign=YOUR_SIGN" \
-H "Content-Type: application/json" \
-d '{"msgtype":"text","text":{"content":"安全测试消息"}}'
4. 日志检查:查看业务系统日志,确认发送请求返回状态码为 200 且 errcode 为 0。
常见坑
1. 出口 IP 变动:如果使用云函数或某些容器服务,出口 IP 可能是动态的,此时 IP 白名单会导致发送失败。需确认基础设施的网络架构。
2. 签名时间戳误差:加签机制依赖时间戳,如果服务器时间不同步,签名会失效。确保服务器 NTP 同步正常。
3. 关键词匹配:如果还开启了关键词匹配,消息内容必须包含设定关键词,否则会被拦截。
4. URL 编码问题:签名计算后的字符串必须进行 URL Encode,否则特殊字符会导致签名验证失败。
参考来源
1. 钉钉开放平台 - 自定义机器人接入
URL: https://open.dingtalk.com/document/organapp/custom-robot-access