2016-11-18 39 views
2

解释有点长,请耐心等待。请求正文中的Facebook信使API不完整内容

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

在我的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"}}]}]} 

回答

4

我认为问题是一些特定的字符,如@和%需要转换为th eir unicode转义序列,如其文档中所指定的,并替换为原始字符串化的JSON。我转换它们,然后计算新字符串的hmac签名并匹配。

此外,它的工作原因,为什么它不是在某些情况下,我认为是因为字符串中正在被串行化的特殊字符。如果它没有字符@或%,那么它的工作没有任何问题。

这是我如何解决它 - 里面if var hmac,calculatedSignature,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!'); 
    }