Хеширование JSON в PHP не дает того же результата, что и в Javascript для символов Юникода - PullRequest
1 голос
/ 04 октября 2010

Мое веб-приложение связывается с сервером по протоколу JSON. Перед отправкой каждого сообщения JSON из веб-приложения я запускаю на нем функцию hmac-sha1 (для уже закодированного объекта) и вставляю полученный HMAC в заголовок запроса JSON.

На стороне сервера я декодирую сообщение JSON с помощью PHP, извлекаю HMAC, отменяю () HMAC из объекта, а затем кодирую объект обратно в JSON и создаю его HMAC.

HMAC совпадают, если я не использую такие символы, как "ž, š, č". Когда я использую эти символы в сообщении, HMAC больше не совпадают.

В веб-приложении я использую jQuery.post () для передачи уже закодированной строки JSON.

Если я отправлю данные, полученные из веб-приложения, обратно в ответ в кодировке JSON, приложение отобразит «ž, č, š» просто замечательно.

Как я могу настроить соответствие HMAC?

UPDATE: Это проблема только в последних версиях Firefox и Opera. Он отлично работает на IE8 и Chrome. В предыдущих браузерах строка JSON (перед отправкой):

{"body":[{"name":"Žiga Kraljevič","email":"test@email.com","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4259d6ef8f477c020d644409cc16dd9c42301e8"}}

В то время как в последних браузерах (IE8 и Chrome, где это работает) работает следующее:

{"body":[{"name":"\u017diga Kraljevi\u010d","email":"test@email.com","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4e9e2d0d8d11728a2b4329ad6dacdb9409b1de1"}}

Ответы [ 2 ]

2 голосов
/ 04 октября 2010

Вы, вероятно, сталкиваетесь с несколькими проблемами.Одним из них может быть то, что кодировка символов, используемая на клиенте, отличается от кодировки, используемой на сервере, и стоит убедиться, что они одинаковы (подробнее о кодировке символов в превосходное эссе Джоэла ).Другой может быть, что есть несколько правильных способов кодирования вещей.Кодировщики вполне могут использовать разные способы.Например, вы можете закодировать " в строке как \" или \u0022.Оба действительны, и они эквивалентны, но хэши не будут совпадать.Точно так же я немного удивлен, что вы не столкнетесь с большими трудностями, когда не используете акцентированные символы, например с пробелами.

1 голос
/ 05 октября 2010

Какова ваша функция hmac-sha1, откуда она? Если он принимает JSON String в качестве входных данных, то здесь происходит неявный шаг кодирования в байты, поскольку SHA1 работает с байтами, а не с единицами кода UTF-16, такими как JS String.

Я подозреваю, что ваша JS-функция использует кодирование типа «одна кодовая единица n на байт n» для простых вычислений с помощью таких инструментов, как getCharCodeAt. Это фактически то же самое, как если бы ввод строки символов был закодирован в ISO-8859-1. Принимая во внимание, что если вы используете encodeURIComponent или публикуете необработанные символы через XMLHttpRequest, неявная кодировка там - UTF-8.

Вы можете преобразовать String в формат UTF-8-байтов-хранимых-в-единицах кода для функции JS hmac-sha1, которая может сделать ее соответствующей PHP. Для этого есть хитрая идиома:

var utf8= unescape(encodeURIComponent(s));

При размещении JSON I base64 и в любом случае urlencode

URL-кодирования должно быть достаточно (с encodeURIComponent, а не escape, что является неправильным для абсолютно всего , за исключением обратного шага уловки преобразования UTF-8 выше).

Кстати, какова цель этого? Вы знаете, что это никак не защищает соединение между браузером и сервером, да?

Edit:

Я использую jssha.sourceforge.net для sha1-hmac. В PHP я использую hash_hmac.

У меня работает:

var data= '\u017E, \u010D, \u0161'; // 'ž, č, š' in a Unucode string
var utf8bytes= unescape(encodeURIComponent(data));
var hmac= new jsSHA(utf8bytes).getHMAC('foo', 'ASCII', 'SHA-1', 'HEX');
alert(hmac); // 5d15f0b9...
var form= 'message='+encodeURIComponent(data)+'&hmac='+encodeURIComponent(hmac);
xmlhttprequest.send(form);

...

$utf8bytes= $_POST['message']; // "\xc5\xbe, \xc4\x8d, \xc5\xa1"
                               // which is 'ž, č, š' as UTF-8 in byte string
$hmac= hash_hmac('sha1', $utf8bytes, 'foo');
echo $hmac; // 5d15f0b9...
echo strtolower($hmac)===strtolower($_POST['hmac']); // true

Используется двоичный ('ASCII' to jsSHA) ключ foo. Если вы используете двоичный ключ с символами, отличными от ASCII, вам необходимо убедиться, что эти также правильно закодированы, так же, как данные.

Ключ для HMAC - это общий секрет между сервером и клиентом, который ранее был обменен по безопасному соединению.

Это не только ключ, который вы должны будете отправить через безопасное соединение, но и вся страница и все сценарии в ней. В противном случае человек в середине атаки может саботировать ваши скрипты по пути в браузер, чтобы заменить их версией, которая использовала секретный ключ для подписи поддельных сообщений. Если у вас есть HTTPS-сервер для всего этого, хорошо. Я не уверен, что HMAC будет делать в этом случае, хотя, кажется, это немного связано с анти-XSRF-схемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...