【问题标题】:Facebook Messenger Verify X-Hub-Signature of Shared LocationFacebook Messenger 验证共享位置的 X-Hub 签名
【发布时间】:2017-12-07 04:46:37
【问题描述】:

我正在向我的 Messenger 应用程序添加 X-Hub 验证。我是在这里了解到的:https://developers.facebook.com/docs/messenger-platform/webhook-reference

我已成功通过验证来处理简单的短信,但是当我发送位置而不是短信时,验证失败,因为我生成的哈希值与 Facebook 在标题中给我的哈希值不匹配。这是我的验证码:

module.exports.requestIsValid = function(event) {
    if (event['headers']['X-Hub-Signature']) {
        var sha     = event['headers']['X-Hub-Signature']
        var body    = JSON.stringify(event.body);
        return sha == `sha1=${crypto.createHmac('sha1', config.APP_SECRET).update(body).digest('hex')}`;
    }

    return false;   // this return is never called, I know that the first return is the one returning false when it should be true
 }

以下是常规文本消息负载的示例:

{"body":{"object":"page","entry":[{"id":"1366222643461024","time":1499114399253,"messaging":[{"sender":{"id ":"1582085681843981"},"recipient":{"id":"1366222643461024"},"timestamp":1499114399084,"message":{"mid":"mid.$cAASAZhi0_wRjO3OtbFdCi5lV2qe4","seq":52192," text":"Test"}}]}]},"method":"POST","principalId":"offlineContext_authorizer_principalId","headers":{"X-Real-Ip":"173.252.88.182","X -Forwarded-For":"173.252.88.182","Host":"test.localtunnel.me","X-Forwarded-Proto":"https","X-Nginx-Proxy":"true","Connection ":"close","Content-Length":"270","Accept":"/","Accept-Encoding":"deflate, gzip","Content-Type":" application/json","X-Hub-Signature":"sha1=0f51d788fe5f1111846097ad016728cdcd06029f"},"query":{},"path":{},"identity":{"accountId":"offlineContext_accountId","apiKey" :"offlineContext_apiKey","caller":"offlineContext_caller","cognitoAuthenticationProvider":"offlineContext_cognitoAuthenticationProvider","cognitoAuthenticationType":"offlineContext_cognitoAuthenticationType","sou rceIp":"127.0.0.1","user":"offlineContext_user","userAgent":"","userArn":"offlineContext_userArn"},"stageVariables":{},"isOffline":true}

下面是一个带有位置的有效负载示例:

{"body":{"object":"page","entry":[{"id":"1366222643461024","time":1499114451619,"messaging":[{"sender":{"id ":"1582085681843981"},"recipient":{"id":"1366222643461024"},"timestamp":1499114451469,"message":{"mid":"mid.$cAASAZhi0_wRjO3R6DVdCi8v9yqk0","seq":52196," attachments":[{"title":"Brandon 的位置","url":"https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.bing.com%2Fmaps%2Fdefault.aspx%3Fv%3D2%26pc%3DFACEBK%26mid%3D8100%26where1%3D35.142236316764%252C%2B-106.53531087607%26FORM%3DFBKPL1%26mkt%3Den-US&h=ATOu8uYrLDiFl6wG8RVfhXvwkMl7uB_l2MHqB_uKLhk8qC9p1ua0EOLpGkznVX7Y8YfxSXP7vDuAR7swPmDCw1esH2bwKhNNsZKxVPC2ViC2AFMO_g&s=1&enc=AZMYxff8btvCZWHtzUR4oFL7K2Mg6nXM_O_tRXXL-L8z508UAOauiSRztoRvWdlGCWU1dNRdNK1ls2CGulM8lvzR","type":"location","payload":{"coordinates":{"lat":35.142236316764,"long ":-106.53531087607}}}]}}]}]},"method":"POST","principalId":"offlineContext_authorizer_principalId』,"headers":{"X-Real-Ip":"173.252.90.239", "X-Forwarded-For":"173.252.90.239","Host":"test.localtunnel.me","X-Forwarded-Proto":"https","X-Nginx-Proxy":"true", "Connection":"close","Content-Length":"911","Accept":"/","Accept-Encoding":"deflate, gzip","Content-Type" :"application/json","X-Hub-Signature":"sha1=34f23436b2744b9b0cc8776922e7386c454786db"},"query":{},"path":{},"identity":{"accountId":"offlineContext_accountId"," apiKey":"offlineContext_apiKey","caller":"offlineContext_caller","cognitoA uthenticationProvider":"offlineContext_cognitoAuthenticationProvider","cognitoAuthenticationType":"offlineContext_cognitoAuthenticationType","sourceIp":"127.0.0.1","user":"offlineContext_user","userAgent":"","userArn":"offlineContext_userArn"}," stageVariables":{},"isOffline":true}

如果需要,很乐意提供额外信息。

更新: 经过进一步检查,似乎只有在有效负载中存在“附件”字段时,验证才会失败。因此,如果我发送图片或 gif 或类似的东西时也会失败。

【问题讨论】:

  • 您不应该自己对数据进行字符串化(即使是最微小的差异也会使哈希无效),而应该从您的应用程序首先收到的原始帖子正文创建哈希。
  • @CBroe 当我省略 stringify 时,我收到此错误 - TypeError: Data must be a string or a buffer。看起来它来自我正在使用的加密节点模块

标签: facebook security postback sha facebook-messenger


【解决方案1】:

您应该将 SHA1 算法应用于“原始请求正文”。如果您解析 body 并将其转换回 json;它可能不起作用。

【讨论】:

  • 如果你想按原样调试 Facebook webhook 请求,你可以使用 chatbotproxy.com
  • 好吧,这是有道理的,不幸的是,当我省略 stringify 时,我得到了这个错误 - TypeError: Data must be a string or a buffer。看起来它来自我正在使用的加密节点模块
  • 你可以把它串起来。它会起作用的。如果您不进行字符串化并将其发送到加密,它将引发该错误。看我的回答
【解决方案2】:

你的bodyParserJSON应该返回rawBody

bodyParser.json({
    verify(req, res, buf) {
      req.rawBody = buf;
    },
})

这是我编写的中间件。它使用crypto模块生成sha1

fbWebhookAuth: (req, res, next) => {
    const hmac = crypto.createHmac('sha1', process.env.FB_APP_SECRET);
    hmac.update(req.rawBody, 'utf-8');
    if (req.headers['x-hub-signature'] === `sha1=${hmac.digest('hex')}`) next();
    else res.status(400).send('Invalid signature');
}

最后在您的路线中,您可以将其用作:

app.post('/webhook/facebook', middlewares.fbWebhookAuth, facebook.webhook);

【讨论】:

    【解决方案3】:

    如果你使用 express js

    app.use(express.json({
    verify:(req, res, buf)=>{
      req.rawBody = buf;
    }}))
    

    你的中间件

    const fbWebhookAuth = (req, res, next) => {
    const hmac = crypto.createHmac('sha1', process.env.FB_APP_SECRET);
    hmac.update(req.rawBody);
    if (req.headers['x-hub-signature'] === `sha1=${hmac.digest('hex')}`) next();
    else res.status(400).send('Invalid signature'); }
    

    你的端点

    app.post('/webhook/Facebook', fbWebhookAuth, facebook.webhook);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 2013-06-17
      • 1970-01-01
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      相关资源
      最近更新 更多