Zoho подписка проверить подпись webhook NodeJS - PullRequest
3 голосов
/ 24 февраля 2020

Я пытаюсь защитить мою реализацию Zoho webhook. Я следовал за этим делом c: https://www.zoho.com/subscriptions/kb/webhooks/securing-webhooks.html

Мне не очень понятно, что делать, но я уверен, что в конце концов я все же сделал все что они сказали.

У меня нет параметров запроса. Формат по умолчанию JSON полезная нагрузка НЕТ X- WWW-FORM-URLENCODED.

Я пытался с помощью следующего кода, но я не получил правильный ха sh. Также неясно, должен ли я сортировать полезную нагрузку по умолчанию или нет. Согласно этому ответу, это необходимо только для параметров, закодированных в форме URL, и параметров запроса, но для простого JSON полезная нагрузка не требуется. В любом случае я пробовал оба способа с последующей реализацией в результате:

function computeZohoSignature(query, payload) {
    return crypto
         .createHmac('sha256', process.env.ZOHO_WEBHOOK_SECRET)
         .update(JSON.stringify(payload), 'utf8')
         .digest('hex');
}

function validSignature(signatureHash, computedHash) {
  return signatureHash.length === computedHash.length
     && crypto.timingSafeEqual(Buffer.from(signatureHash), Buffer.from(computedHash));
} 

Я также пытался обернуть полезную нагрузку следующей функцией:

function sortObjectByKeys(object) {
  if (!isObject(object)) return object;

  const sortedObj = {};
  Object
    .keys(object)
    .sort()
    .forEach((k) => {
      sortedObj[k] = sortObjectByKeys(object[k]);
    });

  return sortedObj;
}

Сортировка работает правильно, и я даже пытался просто отсортировав "root -ключи". Неважно, что я пытаюсь, ха sh никогда не бывает прежним. И ДА Я на 100% уверен, что секрет верен, я трижды проверил это.

Кто-нибудь видит, что здесь не так, или у него есть рабочая NodeJS реализация этого?

Спасибо в заранее!

1 Ответ

1 голос
/ 26 февраля 2020

Типичная Express установка использует следующую конфигурацию для разбора:

app.use(bodyParser.json());

Этот синтаксический анализатор добавляет проанализированный (объект) содержимое тела запроса к body свойство первого req параметра вашего обработчика маршрута (req, res) => { ... }.

Однако значение ha sh вашего веб-крючка рассчитывается на основе полезной нагрузки raw (string). Хотя вы можете использовать JSON.stringify для преобразования вашего проанализированного тела обратно в строку, это может привести к несоответствиям с исходной необработанной полезной нагрузкой.

Например, если ваша валюта Euro, Zoho передаст закодированный код "\u20a" как значение для currency_symbol. Однако, если вы используете JSON.stringify для преобразования вашего проанализированного тела обратно в строку, вы обнаружите, что вместо него создается незашифрованный "€". И поскольку это приводит к тому, что обе строки не являются идентичными, они не будут давать одинаковые значения. body & результат вашего JSON.stringify и, таким образом, как последний должен быть преобразован, чтобы он был в том же формате, что и исходное сырое тело. Самый простой способ преодолеть это - использовать метод вашего синтаксического анализатора verify, чтобы добавить необработанное тело, например, к. свойство rawBody первого параметра req вашего обработчика маршрута, как описано в этой статье :

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

Если вы присваиваете значение req.rawBody для payload ha sh, полученный вашим computeZohoSignature методом, теперь должен соответствовать подписи, переданной Zoho!

...