Крипто в NodeJS дает сбой, когда символы Юникода
Я пытаюсь проверить целостность данных с помощью библиотеки NodeJS Crypto. Это требует вычисления Hmac строки JSON.
После некоторого теста я смог обнаружить проблему: это происходит всякий раз, когда он содержит символ Unicode. Например:
var hasher = crypto.createHmac("sha256", 'secret_key');
hasher.write('{"timezone":"(GMT-05:00) Eastern Time (US \u0026 Canada)"}');
hasher.end();
var calculatedHmac = new Buffer(hasher.read(), 'utf8').toString('base64');
console.log(calculatedHmac);
Однако это возвращает неправильный HMAC. Тот же код в PHP соответствовал подписи, которую я получил от стороннего сервиса:
$data = '{"timezone":"(GMT-05:00) Eastern Time (US \u0026 Canada)"}';
$calculated_hmac = base64_encode(hash_hmac('sha256', $data, 'secret_key', true));
var_dump($calculated_hmac); // Result is correct here
Если я удалю "\u0026" из полезной нагрузки NodeJS, то получу тот же правильный результат, что и в PHP.
Я что-то здесь не так делаю?
Спасибо!
2 ответа
\uXXXX
Нотация escape-последовательности поддерживается только PHP версии 7 ( ссылка).
Если вы используете более старую версию PHP, эти escape-последовательности будут переданы буквально (так \u0026
является 6-символьной подстрокой), тогда как узел будет интерпретировать его как один символ (&
).
Если вы хотите, чтобы Node прекратил интерпретацию escape-последовательности, вам нужно экранировать обратную косую черту:
hasher.write('{"timezone":"(GMT-05:00) Eastern Time (US \\u0026 Canada)"}');
Когда вы это сделаете, результат для Node и PHP будет одинаковым (0CE0++Kn9mi5xd7nAz/mWOrr7939RWwzfxhBzxAWtAk=
если быть точным).
Я не эксперт по PHP, но у меня есть хорошее предположение:
Вы должны столкнуться с проблемой кодировки. Вы явно конвертировали свой буфер в UTF-8 в файле node.js. Таким образом, у вас есть хэш из двоичного представления строки в кодировке UTF-8.
Бьюсь об заклад, PHP внутренне имеет дело с другой кодировкой (возможно, Unicode), которая обеспечит другое двоичное представление вашей строки.
Чтобы все было правильно, вы должны обеспечить преобразование обоих в одно и то же двоичное представление перед хэшированием.
Обновление: я только что заметил, что вы хэшировали строку напрямую и конвертировали ее в UTF8. Вы должны инвертировать это поведение: переведите свою строку в UTF-8 ПЕРЕД хэшированием. И вы должны сделать то же самое в PHP. Обе платформы должны согласовать кодировку перед хэшированием.