Неполный контент API мессенджера Facebook в теле запроса

Объяснение немного длинное, поэтому, пожалуйста, потерпите меня.

Я создаю бота для обмена сообщениями в Facebook, который использует мой сервер Sails.js/node.js в бэкэнде и базу данных MongoDB.

В моем приложении для парусов я применил политики к методу контроллера, который обрабатывает операции, которые необходимо выполнить после получения текста от пользователя. В этой политике я следую документации (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"}}]}]}

person Simple_Programmer    schedule 18.11.2016    source источник


Ответы (2)


Я думаю, что проблема заключалась в том, что некоторые определенные символы, такие как @ и %, необходимо было преобразовать в их escape-последовательность Unicode, как указано в их документации, и заменить в исходном строковом JSON. Я преобразовал их, а затем вычислил сигнатуру hmac новой строки, и она совпала.

Кроме того, я думаю, что причина, по которой это работало, а в некоторых случаях - нет, заключалась в том, что в строке, которая была преобразована в строку, присутствовали специальные символы. Если в нем не было символов @ или %, то все работало без проблем.

Вот как я это решил: внутри if var hmac, calculateSignature, 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!');
    }
person wadali    schedule 23.11.2016

Ваш 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);
person Gijo Varghese    schedule 21.05.2018