Python discord_interactions库verify_key函数报错:签名伪造或损坏
Discord机器人交互端点签名验证失败问题排查
问题描述
我编写了用于Discord机器人交互端点验证的代码片段:
def interactions_view(request): if request.method == 'POST': try: raw_body = request.body signature = request.headers.get('X-Signature-Ed25519') timestamp = request.headers.get('X-Signature-Timestamp') logger.debug(f"Signature (type: {type(signature)}): {signature}") logger.debug(f"Timestamp (type: {type(timestamp)}): {timestamp}") logger.debug(f"Raw Body (type: {type(raw_body)}): {raw_body}") if not signature or not timestamp: return JsonResponse({'Error': 'Missing signature or timestamp'}, status=400) try: verify_key(raw_body, signature, timestamp, PUBLIC_KEY) except Exception as e: logger.error(f"Signature verification failed: {e}") return JsonResponse({'Error': 'Signature verification failed'}, status=401) . . .
服务器日志返回错误:
2024-06-29T22:14:41.227687+00:00 app[web.1]: Signature was forged or corrupt
且Discord发送POST请求时始终返回200 OK状态码。我尝试对密钥进行编解码转换,出现“could not concatenate str object to bytes”等不同错误,也进行了日志调试,但问题仍未解决,请问哪里遗漏或操作有误?
问题排查与解决方法
1. 签名参数编解码不符合要求
Discord Ed25519签名验证要求所有核心参数必须是字节类型,且需按正确格式处理:
signature:从十六进制字符串解码为字节(bytes.fromhex(signature))timestamp:转换为UTF-8编码的字节(timestamp.encode('utf-8'))PUBLIC_KEY:从十六进制字符串解码为字节(bytes.fromhex(PUBLIC_KEY))- 验证时需将
timestamp字节与raw_body字节拼接,作为待验证的消息体,而非单独传入两个参数
修正后的验证逻辑示例(基于PyNaCl库):
from nacl.signing import VerifyKey from nacl.exceptions import BadSignatureError # 处理参数编码 signature_bytes = bytes.fromhex(signature) timestamp_bytes = timestamp.encode('utf-8') public_key_bytes = bytes.fromhex(PUBLIC_KEY) # 拼接timestamp和原始请求体 message = timestamp_bytes + raw_body try: verify_key = VerifyKey(public_key_bytes) verify_key.verify(message, signature_bytes) except BadSignatureError: logger.error("Signature verification failed: forged or corrupt") return JsonResponse({'Error': 'Signature verification failed'}, status=401)
2. 请求体被篡改
- 必须确保
raw_body是请求的原始未修改字节,禁止使用框架解析后的请求体(如Django的request.POST),这类解析会改变原始字节结构,导致签名验证失败 - 检查是否有中间件对请求体进行了解码、修改或压缩,这类操作会破坏签名验证的原始数据
3. 状态码返回逻辑异常
Discord要求验证失败时返回401 Unauthorized,若Discord收到200,说明代码存在未覆盖的分支:
- 检查外层
try-except是否捕获了验证异常并返回了默认200 - 确认验证失败分支的
return语句被正确执行,没有被其他逻辑覆盖
4. 公钥配置错误
- 确认
PUBLIC_KEY是Discord开发者平台中机器人的公钥(十六进制字符串),无多余空格、换行或字符 - 禁止直接传入字符串类型的公钥,必须转换为字节类型后再用于验证
内容的提问来源于stack exchange,提问作者GwenSt11
相关产品推荐
相关产品推荐

