Facebook Webhook签名验证失败问题求助
Facebook Webhook签名验证不匹配问题
我正在开发一款接收Facebook Webhooks payload的应用,每次调用时Facebook会提供签名,我需要验证签名来确保payload的完整性和来源。我严格按照官方文档的步骤和代码实现,用App Secret计算SHA-256签名,但生成的签名始终和Facebook在x-hub-signature-256头里发送的不匹配。
我用Lead Ads测试工具或者Webhook注册页的测试按钮发送请求,自己代码生成的签名和在线HMAC SHA256工具计算的结果一致,但就是和Facebook发来的对不上。我还试过Stack Overflow上的C#代码,生成的签名也和JS代码、在线工具一致,但还是和Facebook的签名不匹配。
我的JavaScript代码
const express = require("express"), bodyParser = require("body-parser"), { urlencoded, json } = require("body-parser"), app = express(); const crypto = require("crypto"); app.use(bodyParser.json({ verify: (req, res, buf) => { req.rawBody = buf } })); function verifyRequestSignature(req, res, buf) { var signature = req.headers["x-hub-signature-256"]; if (!signature) { console.warn(`Couldn't find "x-hub-signature-256" in headers.`); } else { var elements = signature.split("="); var signatureHash = elements[1]; var expectedHash = crypto .createHmac("sha256", "AppSecret") .update(buf) .digest("hex"); console.log(expectedHash); if (signatureHash != expectedHash) { throw new Error("Couldn't validate the request signature."); } } } // Handle incoming requests app.post("/webhook", (req, res) => { try { verifyRequestSignature(req, res, req.rawBody); // Handle the incoming webhook event here... res.status(200).send("EVENT_RECEIVED"); } catch (err) { console.error(err); res.sendStatus(403); } }); // Start the server const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); });
示例数据
App-secret: 3f1e071f97065865829855e7b6e69dc8 Payload: {"entry":[{"id":"0","time":1683656757,"changes":[{"field":"leadgen","value":{"ad_id":"444444444","form_id":"444444444444","leadgen_id":"444444444444","created_time":1683656757,"page_id":"444444444444","adgroup_id":"44444444444"}}]}],"object":"page"} Expected/Calculated signature: f5092edd80ab944fb1c66cf5d2f5534b100e16d18b117187635b55b2f4e6fc91 Signature Received: sha256=6f11c3490dbdf8e63af0287f40ccf159a12cac8e3f3213f09cc1d1247ceaa386
有没有人能帮我找出签名不匹配的原因?
排查方向及解决方案
- 确认App Secret准确性:检查代码中的
AppSecret是否是应用的真实密钥,不要混淆应用ID、页面AccessToken等其他凭证,确保没有额外的空格或换行符。 - 校验原始请求体一致性:Facebook基于原始字节流计算签名,你需要确认
rawBody是未被修改的请求原始数据。可以打印buf.toString()和测试工具发送的Payload逐字符对比,排查是否有中间件(代理、负载均衡)修改了请求体的空格、编码或转义字符。 - 检查字符编码:确保计算HMAC时使用的是Payload的UTF-8编码字节流,Node.js的
crypto.update默认处理Buffer,避免将buf转成其他编码的字符串后再传入计算。 - 测试真实请求:Lead Ads测试工具的请求可能和真实生产请求有细微差异,尝试触发一次真实的Lead Ads Webhook请求,再验证签名是否匹配。
- 排查中间件干扰:确认没有其他Express中间件(如压缩、解码类中间件)在
body-parser前后修改了请求体,这会直接导致原始字节流变化,哈希计算错误。
内容的提问来源于stack exchange,提问作者Vatsal Arya
相关产品推荐
相关产品推荐

