Крипто в 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. Обе платформы должны согласовать кодировку перед хэшированием.

Другие вопросы по тегам