【问题标题】:Facebook messenger API incomplete content in request body请求正文中的 Facebook Messenger API 内容不完整
【发布时间】:2016-11-18 13:38:08
【问题描述】:

解释有点长,请多多包涵。

我正在构建一个 Facebook Messenger 机器人,它在后端使用我的sails.js/node.js 服务器和一个 MongoDB 数据库。

在我的sails 应用程序中,我已将策略应用于控制器的方法,该方法处理接收到用户的文本后要执行的操作。在此策略中,我遵循文档(https://developers.facebook.com/docs/messenger-platform/webhook-reference - “安全”部分)并将请求标头中的 x-hub-signature 与请求有效负载(正文)的 sha1 摘要进行比较。

所以现在每当我向机器人发送消息时,它在策略中说明请求的签名和我计算的签名不同,因此不会更进一步。我仔细检查了计算摘要时应该使用的应用程序密码,它似乎是正确的。我发现的另一个区别是,Facebook 请求还在其标头中发送了一个“内容长度”字段,这与它们在同一请求中发送的正文的字符长度不同。这就是我认为不同签名的原因,但我无法解决它并找到问题的根源,为什么会发生这种情况。

另外需要注意的是,引发此不匹配错误的相同代码在某些时候(实际上是大多数时候)完美运行。

那么有人可以帮我吗?我将永远感激:)

这是政策中的代码

var crypto = require('crypto');
if(req.headers['x-hub-signature']){
    //console.log('req headers -----', JSON.stringify(req.headers));
    //console.log('req body -----', JSON.stringify(req.body));

    var hmac, calculatedSignature, payload = req.body;
    hmac = crypto.createHmac('sha1', app_secret);
    hmac.update(JSON.stringify(payload));
    calculatedSignature = 'sha1='+hmac.digest('hex');

    //console.log("signature calculatedSignature",calculatedSignature);
    if(calculatedSignature === req.headers['x-hub-signature']){
        return next();
    }else{
        res.forbidden('You shall not pass!');
    }
}

这是一个示例请求标头 -

{"host":"e93d4245id.ngrok.io","accept":"*/*","accept-encoding":"deflate, gzip","content-type":"application/json","x-hub-signature":"sha1=d0cd8177add9b1ff367d411942603b0d08183964","content-length":"274","x-forwarded-proto":"https","x-forwarded-for":"127.0.0.1"}

这是来自同一个请求的正文 -

{"object":"page","entry":[{"id":"1778585282425767","time":1479476014038,"messaging":[{"sender":{"id":"userId"},"recipient":{"id":"recipientId"},"timestamp":1479468097895,"message":{"mid":"mid.1479468097895:efdc7d2c68","seq":2355,"text":"Hahahaha"}}]}]}

【问题讨论】:

    标签: javascript node.js sails.js facebook-messenger messenger


    【解决方案1】:

    我认为问题在于需要将某些特定字符(例如 @ 和 %)转换为其文档中指定的 unicode 转义序列,并在原始字符串化 JSON 中替换。我对它们进行了转换,然后计算了新字符串的 hmac 签名并得到了匹配。

    我认为它工作的原因以及在某些情况下不工作的原因是因为该字符串中存在特殊字符,该字符串正在被字符串化。如果它没有字符 @ 或 % 那么它可以正常工作。

    这就是我解决它的方法 - 里面if var hmac, computedSignature, payload = JSON.stringify(req.body);

        var resStr = payload.replace(/\@|\%/g,function(a, i){
            hex = payload.charCodeAt(i).toString(16);
            var s = "\\u" + ("000"+hex).slice(-4);
            return s;
        });
    
        hmac = crypto.createHmac('sha1', app_secret);
        hmac.update(resStr);
        calculatedSignature = 'sha1='+hmac.digest('hex');
    
        if(calculatedSignature === req.headers['x-hub-signature']){
            return next();
        }else{
            res.forbidden('You shall not pass!');
        }
    

    【讨论】:

      【解决方案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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-29
        • 1970-01-01
        • 2012-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-26
        • 1970-01-01
        相关资源
        最近更新 更多