You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask中无法验证Meta/WhatsApp Webhook的X-Hub-Signature-256,求排查或示例

Flask中Meta/WhatsApp Webhook的X-Hub-Signature-256签名验证问题

我在Flask框架中无法成功验证Meta/WhatsApp Webhook的X-Hub-Signature-256签名,希望有人帮忙排查代码错误,或者提供可正常运行的示例。我的代码实现如下:

import base64
import hashlib
import hmac
import os

from dotenv import load_dotenv
from flask import Flask, jsonify, request
from werkzeug.middleware.proxy_fix import ProxyFix

load_dotenv()

API_SECRET = os.environ.get('API_SECRET')

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1)


def verify_webhook(data, hmac_header):

    hmac_recieved = str(hmac_header).removeprefix('sha256=')
    digest = hmac.new(API_SECRET.encode('utf-8'), data,
                      digestmod=hashlib.sha256).digest()
    computed_hmac = base64.b64encode(digest)

    return hmac.compare_digest(computed_hmac, hmac_recieved.encode('utf-8'))


@app.route("/whatsapp", methods=["GET", "POST"])
def whatsapp_webhook():


    if request.method == "POST":

        try:
            data = request.get_data()

            if not verify_webhook(data, request.headers.get('X-Hub-Signature-256')):
                return "", 401

        except Exception as e:
            print(e)
            return "", 500

    return jsonify({"status": "success"}, 200)

问题排查与修复方案

  1. 密钥混淆问题
    很多人会把Webhook的Verify Token和Meta应用的App Secret搞混——X-Hub-Signature-256签名验证必须使用App Secret(可在Meta开发者后台的应用设置中找到),而非Webhook配置页的Verify Token。先确认你的API_SECRET环境变量对应的是正确的App Secret。

  2. 空Header处理漏洞
    若请求未携带X-Hub-Signature-256头,你的代码会把None转成字符串"None"再执行removeprefix,直接导致验证逻辑失效。需先判断Header是否存在且格式正确,不存在直接返回验证失败。

  3. 编码匹配细节优化
    原代码中computed_hmac是base64编码后的bytes对象,与hmac_recieved.encode('utf-8')的bytes比较逻辑可行,但转成字符串后再比较可读性更强,也能避免潜在编码问题。

修复后的可运行代码

import base64
import hashlib
import hmac
import os

from dotenv import load_dotenv
from flask import Flask, jsonify, request
from werkzeug.middleware.proxy_fix import ProxyFix

load_dotenv()

# 提前校验API_SECRET是否存在
API_SECRET = os.environ.get('API_SECRET')
if not API_SECRET:
    raise ValueError("API_SECRET环境变量未设置或为空")

# 单独配置Webhook验证用的Verify Token
VERIFY_TOKEN = os.environ.get('VERIFY_TOKEN')
if not VERIFY_TOKEN:
    raise ValueError("VERIFY_TOKEN环境变量未设置或为空")

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1)


def verify_webhook(data, hmac_header):
    # 先校验Header的存在性与格式
    if not hmac_header or not hmac_header.startswith('sha256='):
        return False
    
    hmac_received = hmac_header.removeprefix('sha256=')
    # 生成计算签名
    digest = hmac.new(
        API_SECRET.encode('utf-8'),
        data,
        digestmod=hashlib.sha256
    ).digest()
    computed_hmac = base64.b64encode(digest).decode('utf-8')
    
    # 使用安全比较方法避免时序攻击
    return hmac.compare_digest(computed_hmac, hmac_received)


@app.route("/whatsapp", methods=["GET", "POST"])
def whatsapp_webhook():
    if request.method == "GET":
        # 处理Meta的Webhook订阅验证请求
        mode = request.args.get('hub.mode')
        token = request.args.get('hub.verify_token')
        challenge = request.args.get('hub.challenge')
        
        if mode and token and mode == 'subscribe' and token == VERIFY_TOKEN:
            return challenge, 200
        return "", 403
    
    elif request.method == "POST":
        try:
            # 必须获取原始请求体,不能提前解析JSON(会修改请求体导致签名不匹配)
            data = request.get_data()
            hmac_header = request.headers.get('X-Hub-Signature-256')
            
            if not verify_webhook(data, hmac_header):
                return "", 401
            
            # 此处添加Webhook事件处理逻辑,例如:
            # event = request.get_json()
            # print("收到事件:", event)
            
        except Exception as e:
            print(f"验证或处理出错: {e}")
            return "", 500
    
    return jsonify({"status": "success"}), 200

额外注意事项

  • 验证签名前禁止调用request.get_json()或其他解析请求体的方法,否则请求体格式会被修改,导致签名不匹配。
  • 若应用部署在反向代理(如Nginx)后,需确保代理未修改请求体或请求头,ProxyFix中间件已处理X-Forwarded-*头,但仍需确认代理配置正确。
  • 测试时可通过curl模拟携带正确签名头的请求,验证逻辑是否正常。

内容的提问来源于stack exchange,提问作者Gurkenkönig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:25:14