Подписываем данные: HMAC на практике в API и Web-формах

HMAC (сокращение от англ. hash-based message authentication code, код проверки подлинности сообщений, использующий односторонние хеш-функции) — в криптографии, один из механизмов проверки целостности информации, позволяющий гарантировать то, что данные, передаваемые или хранящиеся в ненадёжной среде, не были изменены посторонними лицами (атака типа «man in the middle»).

К таким данным могут относиться например данные, передаваемые в запросах API, когда критически важна целостность передаваемой информации, или же при передаче данных из Web-форм.

Зачем это нужно?


Если отойти от научной формулировки, что же такое подпись данных и как это реализуется на практике?

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

Например, мы имеем исходный массив данных вида:

$data = array(
  'param1' => 'value1', 
  'param2' => 'value2',
  'param3' => 'sometext',
  'a' => 'b'
);

Самое простое, что мы можем сделать – это каким-то образом сериализовать массив (привести его в строковое представление), добавить в конец получившейся строки некий секретный ключ – набор символов известный только нам и получателю данных (пусть будет “mysecretkey”), после чего применить к этому какую-нибудь хеш-функцию, скажем, md5.

Какие можно встретить практические решения? В зависимости от того, важны ли значения массива или его ключи, можно встретить, например, такие реализации:

$hash = md5(implode(";",array_keys($data)).";"."mysecretkey")) = md5("param1;param2;param3;a;mysecretkey")

или

$hash = md5(implode(";",array_values($data)).";"."mysecretkey") = md5("value1;value2;sometext;b;secretkey")

Какие есть плюсы и недостатки у данных реализаций?

Самый первый и очевидный плюс, но он же и единственный – это простота реализации. Минусы? Их масса, как минимум в качестве ключевых недостатков, можно привести:

  • MD5 – уже старый алгоритм, который не считается стойким;
  • Если нарушится последовательность параметров или значений – подпись не сойдется;
  • Как быть с вложенными (многомерными) массивами?
  • Либо ключи, либо значения.

Нужно отметить, что последний недостаток в некоторых случаях, как таковым недостатком и не является – например если мы хотим проверить данные из Web-формы, заполняемой человеком и можем проверить только целостность набора полей, а их значения нам заранее неизвестны.

В частности, таким образом, можно формировать более продвинутые CSRF-токены для форм, используя в качестве секретного ключа какой-нибудь внутренний идентификатор, привязанный к сессии пользователя. Тем самым мы решим сразу две задачи – и защиту от CSRF и контроль целостности набора передаваемых параметров – пользователь уже не сможет «поиграться» с полями формы и попробовать добавить или убрать что-нибудь из параметров.

Остальные три пункта требуют решения. С первым все достаточно просто – используем более современные и стойки хеш-аглоритмы с большей длиной шифрограммы, такие, как SHA256 или SHA512 и спим спокойно.

Второй пункт – тоже решается, если определиться, что элементы массива будут отсортированы по какому-то принципу, скажем, в алфавитном порядке.

Добавлеям перед сериализацией массива:

ksort($data);

в результате чего, получаем массив, отсортированный по ключам в алфавитном порядке, и нам становится не важно, в какой последовательности были переданы переменные в массиве.

Следующая проблема решается уже не так просто. Пока мы работали с плоскими массивами все было достаточно просто – отсортировали, в строчку сложили с каким-нибудь разделителем типа ”;” – и готово. Но как же быть с вложенными (многомерными) массивами?

Во-первых функция ksort не рекурсивная, но это, конечно же не большая проблема и решение было найдено достаточно быстро:

function ksort_recursive(&$array, $sort_flags = SORT_REGULAR) 
{
     if (!is_array($array)) return false;      
     ksort($array, $sort_flags);
     foreach ($array as &$arr) {
         ksort_recursive($arr, $sort_flags);
     }
     return true;
}

Во-вторых, массив с вложенностями линейно в строчку уже не сложишь – нужно придумывать дополнительные правила (то есть, изобретать велосипед), или использовать уже «настоящую» сериализацию, такую как JSON, который учитывал бы все вложенные структуры. Использование JSON также решает и четвертую проблему, так как мы сериализуем сразу весь массив, не ограничиваясь отдельно его ключами или значениями.

Почему именно JSON а не простой serialize PHP? Выбор в пользу JSON упал не случайно, поскольку это очень популярный формат сериализации, с которым будет легко работать не только в PHP, но и в любых других популярных языках программирования, таких как Java. Наша реализация должна быть предельно легко переносима на другие платформы и с использованием JSON-сериализации это будет сделать проще всего.

В этом случае все перечисленные проблемы решаются, но встает вопрос с секретным ключом – делать простую конкатенацию ключа справа конечно можно, но это не очень эстетично, благо в PHP есть реализация HMAC с выбором произвольной хэш-фукции:

hash_hmac(“sha256”,$data,”mysecretkey”);

HMAC реализует дополнительное XOR данных с ключом и оборачивает сверху указанной хеш-функцией. Сам алгоритм внутри HMAC подробно описан в литературе по криптографии, или в википедии и описывать здесь, каким именно образом происходит шифрование данных на ключе мы не будем. Просто будем пользоваться этим стандартным аглоритмом.

Сводя все изложенное вместе, разработаем простой класс, который реализовывал бы все описанные действия для получения подписи с многомерного массива, вне зависимости от того, в какой последовательности находятся ключи внутри массива.

Итак, получился следующий незамысловатый код:

// определим коды ошибок, которые мы будем возвращать.
define("E_UNSUPPORTED_HASH_ALGO",-1);
class HMAC_Generator{
	
	private $key, $algo;
	private $sign_param_name = "hmac";
	
	function __construct($key, $algo = "sha256"){
		$this->key = $key;
		$this->algo = $algo;
	}
	
	function make_data_hmac($data, $key = NULL){
		
		// если не задан ключ в параметре - используем из свойств
		if(empty($key)) $key = $this->key;
		
		// если параметр с подписью есть в массиве - уберем.
		if(isset($data[$this->sign_param_name])) unset($data[$this->sign_param_name]);
		
		// отсортируем по ключам в алфавитном порядке - 
		// на случай, если последовательность полей изменилась
		// например, если данные передавались GET- или POST-запросом.
		HMAC_Generator::ksort_recursive($data);
		
		// сформируем JSON (или другую сериализацию - можно переопределить метрд encode_string)
		$data_enc = $this->serialize_array($data);
		
		// формируем и возвращаем подпись
		return $this->make_signature($data_enc, $key);
	}
	
	
	function check_data_hmac($data, $key = NULL, $sign_param_name = NULL){
		
		// если не задан ключ в аргументах - используем из свойств
		if(empty($key)) $key = $this->key;
		
		// если не задано имя параметра с подписью аргументах в параметре - используем из свойств
		if(empty($sign_param_name)) $sign_param_name = $this->sign_param_name;
		
		// если в данных нет подписи - сразу вернем false
		if(empty($data[$sign_param_name])) return false;
		
		// исходный HMAC нам приходит в том же массиве, что и данные,
		// заберем его значение для сверки и выкинем из массива
		$hmac = $data[$sign_param_name];
		unset($data[$sign_param_name]);
		
		// сформируем контрольный HMAC
		$orig_hmap = $this->make_data_hmac($data, $key);
		
		// проверку осуществляем регистронезависимо
		if(strtolower($orig_hmap) != strtolower($hmac)) return false;
		else return true;
	}
	
	
	// Установка алгоритма хеширования
	
	function set_hash_algo($algo){
		
		// приведем к нижнему регистру
		$algo = strtolower($algo);
		// проверим, поддерживается ли системой выбранный алгоритм
		if(in_array($algo, hash_algos()))
			$this->algo = $algo;
		else return 
			E_UNSUPPORTED_HASH_ALGO;
	}
	
	
	//
	// сериализацию и хеширование - выносим в отдельные методы, просто перепишите или переопределите их
	//
	private function serialize_array($data){
		// кодируем все в json, в случае если мы будем собирать подпись не только в PHP,
		// такой тип сериализации - оптимальный
		$data_enc = json_encode($data, JSON_UNESCAPED_UNICODE);
		return $data_enc;
	}
	
	// переопределите, если будет другой алго формирования подписи, не HASH HMAC
	private function make_signature($data_enc, $key){
		// сформируем подпись HMAC при помощи выбранного аглоритма
		$hmac = hash_hmac($this->algo, $data_enc, $key);
		return $hmac;
	}
	
	// статический метод для рекурсивной сортировки массива по именам ключей
	public static function ksort_recursive(&$array, $sort_flags = SORT_REGULAR) {
		// если это не массив - сразу вернем false
		if (!is_array($array)) return false;
    		ksort($array, $sort_flags);
    		foreach ($array as &$arr) {
			HMAC_Generator::ksort_recursive($arr, $sort_flags);
    		}
    		return true;
	}
}

Вкратце разберем функциональность класса. В свойствах класса объявлены две приватные переменные для ключа и алгоритма, а также переменная $sign_param_name, в которой содержится имя параметра с подписью (по-умолчанию равно “hmac”), который будет использоваться при проверке данных методом check_data_hmac по-умолчанию.

В конструктор передается один обязательный параметр – это секретный ключ. По-умолчанию выбран алгоритм хеш-функции sha256. Можно переопределить алгоритм, передав его вторым параметром в конструктор. В случае, если переданный алгоритм не поддерживается системой, вернется значение константы E_UNSUPPORTED_HASH_ALGO (то есть -1).

Для создания подписи предусмотрен метод:

make_data_hmac($data, [$key])

С ним все довольно просто – обязательный аргумент это данные, можно также использовать для формирования подписи другой секретный ключ, передав его вторым параметром.

Для проверки ранее созданной подписи мы реализовали метод

check_data_hmac($data, [$key], [$sign_param_name])

Метод принимает аргументы:

  • $data – массив с данными;
  • $key – необязательный аргумент, в котором можно передать секретный ключ. Иначе будет использован ключ из свойств объекта;
  • $sign_param_name – имя элемента массива, содержащего контрольную подпись.

Сама подпись при этом должна быть внутри $data в параметре с ключом $sign_param_name. Если последний не передан – то будет использовано имя из свойства объекта $this->sign_param_name.

В остальном логика очень проста – собираем подпись, сравниваем регистронезависимо полученную подпись с подписью, переданной в данных.

Метод set_hash_algo, позволяет поменять алгоритм хеш-функции после создания экземпляра объекта. Функция рекурсивной сортировки массива реализована в качестве статического метода, чтобы ее можно было использовать вне экземпляра объекта где-то еще.

Примеры


Проиллюстрируем работу класса на простом примере:

// данные будут приведены к последовательности param1, param2, param3 в результате работы ksort
$data = array(
	'param3' => 'sometext',
	'param1' => 'value1', 
	'param2' => 'value2',
);
// разные алгоритмы, по-умолчанию - SHA256
$hmac_generator = new HMAC_Generator("myprivatekey");
$hmac_generator_md5 = new HMAC_Generator("myprivatekey","md5");
$hmac_generator_sha1 = new HMAC_Generator("myprivatekey","sha1");

echo "SHA256: ".$hmac_generator->make_data_hmac($data)."\n";
echo "MD5: ".$hmac_generator_md5->make_data_hmac($data)."\n";
echo "SHA1: ".$hmac_generator_sha1->make_data_hmac($data)."\n";

На выходе получим:

SHA256: 7f0a656e00d3a17ab0d04170dfcb4583b4e29e184b9a24d7fed869979d0bf7e8
MD5: 4f91a268c5a8fc4eaa19d7d7cf329583
SHA1: 8c4a7288be7a76fa2c1bd7d481718d1c49d6bca0

Вместо заключения


Мы получили простую реализацию, позволяющую нам подписывать любые данные и проверять переданные подписанные данные. Теперь вы можете подписывать данные, передаваемые через HTTP/REST API, или же создавать продвинутые CSRF-токены для форм и быть уверенными в том, что получаемые данные оригинальны и консистентны.

Все исходные коды доступны в репозитории на GitHub: github.com/idsolutions/HMAC_generator

P.S. Можете форкать и дорабатывать класс на свое усмотрение, комментарии и предложения приветствуются.
Share post

Similar posts

Comments 101

    0
    Тем самым мы решим сразу две задачи – и защиту от CSRF и контроль целостности набора передаваемых параметров – пользователь уже не сможет «поиграться» с полями формы и попробовать добавить или убрать что-нибудь из параметров.

    Какую именно задачу вы пытаетесь тут решить?

    Теперь вы можете подписывать данные, передаваемые через HTTP/REST API

    Подписывать-то можно, но как удостовериться, что данные пришли именно от ожидаемого отправителя? И чем это лучше банального HTTPS?
      0
      Какую именно задачу вы пытаетесь тут решить?

      Задачу валидации входящих данных из Web-формы (убедиться что набор переданных полей соответствует изначальному набору формы и не изменен пользователем), а также защиту формы от CSRF.

      Подписывать-то можно, но как удостовериться, что данные пришли именно от ожидаемого отправителя?

      Если секретный ключ знают только отправитель и получатель данных — по подписи и удостовериться. Вокруг этого собственно все и крутится.

      И чем это лучше банального HTTPS?

      HTTPS шифрует данные, чтобы они не могли быть прочитаны. В случае если реализовать проверку сертификата клиента — то да, можно проверять отправителя — но это сложный способ и непрактичный, если например клиенты обращаются к API, скажем платежного шлюза и посылают запросы, целостность которых должна быть гарантирована.
        0
        Задачу валидации входящих данных из Web-формы (убедиться что набор переданных полей соответствует изначальному набору формы и не изменен пользователем)

        А зачем вообще передавать эти данные через форму тогда, если пользователь не может их изменить?

        также защиту формы от CSRF.

        Каким образом?

        Если секретный ключ знают только отправитель и получатель данных — по подписи и удостовериться.

        Это если отправитель один. А если их много?
          0
          А зачем вообще передавать эти данные через форму тогда, если пользователь не может их изменить?

          Мы говорим о наборе полей, а не самих данных. В форме есть набор полей — зачем пользователю менять сам набор, если он должен заполнить только значения?

          Каким образом?

          Читайте статью: «В частности, таким образом, можно формировать более продвинутые CSRF-токены для форм, используя в качестве секретного ключа какой-нибудь внутренний идентификатор, привязанный к сессии пользователя.» — привязываем «секрет» к сессии и получаем автоматически CSRF-токен.

          Это если отправитель один. А если их много?

          Они передают в параметрах свой ID, ну а система получателя знает секретные ключи для каждого ID и вполне так себе проводит аутентификацию.
          0
          HTTPS шифрует данные, чтобы они не могли быть прочитаны.

          А еще гарантирует, что сообщение не было изменено в пути.

          можно проверять отправителя — но это сложный способ

          Чем он сложнее, чем HMAC, требующий pre-shared secret?

          и непрактичный, если например клиенты обращаются к API, скажем платежного шлюза и посылают запросы, целостность которых должна быть гарантирована.

          Что непрактичного в использовании HTTPS для гарантии целостности запросов?
            0
            HTTPS мы подразумеваем по-умолчанию. HMAC не ставится в противовес или замену HTTPS, а как дополнительный механизм аутентификации и проверки консистентности данных на логическом, а не на транспортном уровне. Улавливаете разницу?
              0
              Какой выигрыш вы получаете, используя HMAC в дополнение к HTTPS?
                0
                Защита логики в формах — раз.
                Аутентификация и защита от изменения пользователем запросов в API, в частности, в платежных формах и платежных API — два.
                  0
                  Можете наглядно показать на примерах? Я вас не понимаю иначе.

                  А то ведь для аутентификации в API достаточно просто передать свой идентификатор, зачем HMAC-то поверх городить?
                    0
                    Есть сервер платежной системы, он принимает запросы на транзакции от клиентов, которых много. Передавая просто идентификтор — мы не можем клиента аутентифицировать. Это первый случай.

                    Второй случай — часто платежная форма инициализируется в виде GET или POST запроса, который происходит на стороне клиента (сабмитится форма в браузере) и в этом случае сервер получающей стороны должен быть уверен что данные сформированы легитимным клиентом и не были изменены. Так понятнее?
                      0
                      Передавая просто идентификтор — мы не можем клиента аутентифицировать.

                      Почему?

                      Второй случай — часто платежная форма инициализируется в виде GET или POST запроса, который происходит на стороне клиента (сабмитится форма в браузере) и в этом случае сервер получающей стороны должен быть уверен что данные сформированы легитимным клиентом и не были изменены.

                      Данные сформированы легитимным клиентом — это та же самая аутентификация, см. выше.
                      Какие данные не были изменены и с какого момента?
                        0
                        Если клиент — это доверенная серверная часть и идентификатор такой, что его нельзя подобрать или угадать — то теоретически можно сделать так, как вы говорите. А если клиент — это форма в браузере пользователя, который может быть зловредным и изменит, скажем, сумму покупки, или идентификатор заказа, или еще какие-то данные, то без HMAC не обойтись и один лишь идентификатор передавать недостаточно.
                          +1
                          Давайте мы не будем путать две разные вещи, а?

                          Еще раз, по порядку.

                          (1) в чем выигрыш от использования HMAC (по сравнению с (а) просто идентификатором (б) идентификатором и паролем (ц) идентификатором и хэшом от пароля + nonce) при аутентификации в API при работе поверх HTTPS?

                          (2) пожалуйста, опишите пошагово сценарий атаки, от которого вы пытаетесь защититься с помощью использования HMAC по форме (и сам способ защиты).
                            0
                            (1) Вы же сами дали ответ на свой вопрос в своём комментарии. В абзаце описании атаки с увеличением длины сообщения вы найдёте ответы, если рассматривать схемы построеные с применением классической схемы Меркла-Дамгарда, коим и является SHA-2.
                              0
                              А причем тут sha-2? Мой вопрос был про работу поверх https.
                                0
                                Вопрос начинался с
                                в чем выигрыш от использования HMAC (по сравнению ...


                                При тестировании веб-приложений в финансовом секторе (о котором не раз упоминал автор) предпалагается, что HTTPS соединение может быть прослушано. Далее ответ на ваш вопрос в предыдущем комментарии.
                                  0
                                  Эээ, кем предполагается?

                                  Ну и да, если https взломан, то понятно, что (а) идентификация плейнтекстом не работает и (б) вообще можно копать могилку, потому что в описываемых автором платежных сценариях по этому https дальше полетят данные моей кредитной карты.
                                    0
                                    Эээ, кем предполагается?

                                    Теми, кто тестирует эти системы. :)

                                    … потому что в описываемых автором платежных сценариях по этому https дальше полетят данные моей кредитной карты.

                                    Автор лишь описывает метод, позволяющий проверить целостность данных, а не их конфеденциальность. И его метод является более защищённым, с точки зрения криптографии, чем просто хэшифрование с секретным значением (и случайными данными). Но и у него есть свои недостатки.
                                      0
                                      Теми, кто тестирует эти системы.

                                      Понимаете, в ряде контекстов такое предположение автоматически делает систему незащищенной (в частности, я тут разрабатываю маленький проектик, так вот там утечка пользовательских данных опасна сама по себе).

                                      Автор лишь описывает метод, позволяющий проверить целостность данных, а не их конфеденциальность. И его метод является более защищённым, с точки зрения криптографии, чем просто хэшифрование с секретным значением (и случайными данными).

                                      Вопрос в области применимости этого метода. Я вот представлю себе две (скорее всего, это не исключительно, но близко): обмен по незащищенным каналам (например, есть hawk, http-аутентификация на основе HMAC) и контроль полномочий третьей стороны без хранения состояния.

                                      Я любопытства ради разверну второй пункт, просто ради демонстрации хода мысли. Условия: есть система А, это api, в нем есть аутентификация и список ресурсов, доступных после аутентификации. Есть система Б, которая относится к тому же решению, но частично физически отделена. Она отдает собственно тела ресурсов (Грубо говоря, Фейсбук-вебсайт и Фейсбук-CDN-с-картинками). Есть клиент (приложение или третий веб-сайт), который идет в api, получает список ресурсов, потом идет в хранилище и достает тела ресурсов на основании адресов, полученных из api. Права клиента со временем могут меняться (т.е., ранее доступный ему ресурс может быть отозван).

                                      Решение (1): заставляем клиент так же аутентифицироваться в хранилище, потом проверяем доступность. Достоинства: самый безопасный подход. контроль доступа настолько полный, насколько это вообще может сделать api. Недостатки: у клиента усложняется процесс обмена (особенно если это браузер и картинки), увеличивается нагрузка на подсистему аутентификации и авторизации.

                                      Решение (2): вместе с каждым адресом ресурса отдаем короткоживущий идентификатор, по нему хранилище проверяет права доступа. Достоинства: клиентский процесс радикально упрощается. Недостатки: идентификатор короткоживущий, а не одноразовый, поэтому отъем прав происходит не мгновенно (точнее, можно сделать мгновенно, но для этого в апи надо делать убийство идентификаторов, это будет очень дорого), и хранилищу все еще надо куда-то ходить, чтобы проверять валидность идентификаторов.

                                      Решение (3): вместе с каждым адресом ресурса отдаем таймстамп + HMAC (от таймстампа), хранилище по HMAC проверяет, что таймстамп действительно пришел от api, и отсчитывает время жизни от него. Достоинства: клиентский процесс такой же простой, как в (2), но хранилищу теперь не надо никуда ходить, достаточно знать shared key. Недостатки: задержка при отъеме прав (причем теперь неустранимая, в отличие от (2)) и… а вроде бы и все. Да?
                                        0
                                        Оффтоп. Вы уже так много материала написали по поводу данной статьи, что можно все комментарии собрать и оформить в виде отдельной статьи со своим видением ситуации.

                                        Про (2) («пожалуйста, опишите пошагово сценарий атаки...») я вообще ничего не писал — этот вопрос относится к автору. Я согласен, что чёткого описания модели угроз в статье нет. Но с другой стороны, это не научная статья, а лишь описание реализации одного из методов (на сколько я это вижу).

                                        А вообще, автор рассматривает один из методов (причём не самый плохой) обеспечения целостности данных, а не универсальный методо защиты от всех существующих и потенциальных атак. Он ничего не упоминает об обеспечении конфеденциальности или неотказуемости (это к ЕЦП).
                                          0
                                          Вы уже так много материала написали по поводу данной статьи, что можно все комментарии собрать и оформить в виде отдельной статьи со своим видением ситуации.

                                          Я не вижу, что я могу сказать нового аудитории — все мои знания так или иначе почерпнуты из литературы и интернетиков.

                                          Про (2) («пожалуйста, опишите пошагово сценарий атаки...») я вообще ничего не писал — этот вопрос относится к автору. Я согласен, что чёткого описания модели угроз в статье нет. Но с другой стороны, это не научная статья, а лишь описание реализации одного из методов (на сколько я это вижу).

                                          Я у вас, вроде, ничего про это и не спрашивал…

                                          А вообще, автор рассматривает один из методов (причём не самый плохой) обеспечения целостности данных, а не универсальный методо защиты от всех существующих и потенциальных атак.

                                          Вопром в том, какие у этого метода преимущества по сравнению с соседними, которые заодно обеспечивают, например, и конфиденциальность.
                                            0
                                            Вопром в том, какие у этого метода преимущества по сравнению с соседними, которые заодно обеспечивают, например, и конфиденциальность.

                                            HTTPS сам по себе обеспечивает лишь конфиденциальность данных, иногда ещё и целостность, при передаче браузер<->сервер (или сервер<->сервер). Но о самих данных он ничего не знает (прсто байтики информации). Ему будет всё ровно «sum=10» или «sum=1000». Проверку целостности «sum» и пытается выполнить автор при помощи HMAC.

                                            Или вы говорите про какие-то другие «соседние методы»?
                                              0
                                              HTTPS сам по себе обеспечивает лишь конфиденциальность данных, иногда ещё и целостность, при передаче браузер<->сервер (или сервер<->сервер). Но о самих данных он ничего не знает (прсто байтики информации). Ему будет всё ровно «sum=10» или «sum=1000».

                                              Эээ, я всегда считал, что если у нас установлено https-соединение, то получающая сторона может быть уверена, что получает именно те данные, которые отправила передающая сторона. Я где-то не прав?

                                              Или вы говорите про какие-то другие «соседние методы»?

                                              Ну, например, можно целиком все сообщение подписывать ЭЦП, или вообще подписывать и шифровать.
                                                +1
                                                Эээ, я всегда считал, что если у нас установлено https-соединение, то получающая сторона может быть уверена, что получает именно те данные, которые отправила передающая сторона. Я где-то не прав?

                                                Нет, почему же, Вы правы. Давайте попробую объяснить немного по другому. Конфеденциальность и целостность данных может происходить на уровне браузера (установлено HTTPS соединение) и на уровне пользователя (сервер проверяет, что данные не были изменены до/после/во время HTTPS сессии). Если HTTPS какием-то образом скомпроментирован, то должен оставаться ещё один уровень безопасности.

                                                Хотя даже я слукавил. Основная цель HTTPS — это проверка того, что вы общаетесь с нужным сервером/клиентом (для защиты от атаки человек посередине). А конфеденциальность и целостность это уже побочные услуги, так сказать в дополнение.

                                                Если сделать предположение, что HTTPS отсутствует (или может быть выполнена атака), то общение с сервером всё ровно должно происходить в защищённом режиме. Или должно быть доказано, что при таких условия злоумышленнику понадобится больше времени для компроментации информации, чем время жизни самой информации.
                                                  0
                                                  Я уже говорил: я привык рассматривать ситуацию «HTTPS скомпроментирован» как автоматическую компроментацию всего приложения, потому что в моем случае конфиденциальность информации превыше всего.

                                                  Вы предлагаете мне строить второй уровень шифрования (именно шифрования) поверх HTTPS?
                                                    0
                                                    Бывает целый ряд задач, когда к доверенному серверу через HTTPS подключается множество недоверенных клиентов, и реализация не предусматривает возможность добавлять авторизацию по клиентским сертификатам. Далеко не ходить за примером — API почти всех платежных систем используют HMAC в том или ином виде.
                                                      0
                                                      (Пойдем по кругу?)

                                                      Во-первых, я говорю про конфиденциальность данных, а вы — про авторизацию. Это разные вещи, и путать их не стоит.

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

                                                      0
                                                      Вы предлагаете мне строить второй уровень шифрования (именно шифрования) поверх HTTPS?

                                                      В критичных приложениях, где без этого не обойтись, — да. В некритичных применять хотя бы целостность сообщений.

                                                      «HTTPS скомпроментирован» как автоматическую компроментацию всего приложения

                                                      А вы не сталкивались с больших компаниями, у которых есть свои ЦС, и которые фильтруют любой трафик, включая HTTPS (и это прописано в политике ИБ)?
                                                        0
                                                        В критичных приложениях, где без этого не обойтись, — да. В некритичных применять хотя бы целостность сообщений.

                                                        Я говорю про свой конкретный сценарий. Если у меня нарушена конфиденциальность — я могу накрываться полотенчиком и ползти на кладбище. Поэтому мне нет смысла строить дополнительный контроль целостности сообщений поверх HTTPS.

                                                        А вы не сталкивались с больших компаниями, у которых есть свои ЦС, и которые фильтруют любой трафик, включая HTTPS (и это прописано в политике ИБ)?

                                                        Сталкивался. Поскольку приложение, над которым я работаю, ориентировано на конкретных конечных пользователей (физиков), никто не ожидает, что они будут его использовать изнутри такой компании. Если же они это делают с компьютера, за которым у них нет контроля, они делают это на свой страх и риск. Дело в том, что внутри такой компании обычно не только есть фильтрация трафика, но и доменный контроль за компьютерами, а в этом случае защитить пользователя очень сложно (хотя и возможно).
                                                          +1
                                                          Я говорю про свой конкретный сценарий.

                                                          Я всё же настаиваю, чтобы вы описали Ваш конкретный сценарий в отдельной статье, и объяснили почему проверка целостности данных, при помощи HMAC, лишняя и не имеет смысла.

                                                          Конкретно в сфере финансов — такой подход оправдан.
                                                            0
                                                            Потому что в моем конкретном сценарии при потере конфиденциальности данных все гарантии сервиса по отношению к пользователю нарушены, и сервис считается неработающим. Это такие входные условия.
                                                              0
                                                              Ну тогда вы уже ответили на вопрос в своём комментарии. Всё зависит от того где и как использовать, и от входных данных конечно же.
                                                                0
                                                                Вот мне и интересен круг задач, в которых HMAC применим. Я свои два примера, где я считаю его оправданным, привел.
                                                                  +1
                                                                  Пример сценария с которым я сталкивался в реальной жизни. Есть мобильное устройство, на котором установлено приложение для оказания финансовых услуг. Предполагается, что первая инициализация приложения происходила через доверенную сеть пользователя, в результате которой сгенерирован секретный ключ на стороне клиента и сервера. Доступ к этим ключам получить не представляется возможным. Доступ к самому приложению не возможен из-за пароля, выбранного пользователем, и блокируется после нескольких попыток ввода неправильного пароля. Предполагается, что приложение переодически пересылает 1 цент на фиксированный счёт. Незащищенный паролем мобильный телефон был украден.

                                                                  Цель злоумышленника перевести деньги на свой счёт и/или изменить количество переводимых денег.

                                                                  Сценарий атаки без HMAC. Устанавливаем один из прокси-серверов с возможностью MitM, например mitmproxy или OWASP ZAP. Устанавливаем корневой сертификат на телефон. Далее перехватываем запрос, изменяем его. Profit.

                                                                  Сценарий атаки c HMAC.
                                                                  Проделывает тоже самое, что и в предыдущем пункте. Только теперь, для того, чтобы изменит сообщение нужно подделать и HMAC, среди данных передаваемого запроса к серверу содержится метка времени. Любая рассинхронизация с сервером более чем на 1 минуту приводит к автоматическому отфильтровыванию сообщения. Хэш (HMAC) берётся от всех полей заголовка http запроса и данных.
                                                                    0
                                                                    В этом сценарии, конечно, есть уйма сомнительных мест (самое дикое из которых — отсутствие certificate pinning), но я вас услышал.
                                                    0
                                                    Ну, например, можно целиком все сообщение подписывать ЭЦП, или вообще подписывать и шифровать.

                                                    В теории действительно более безопасней. А вы пробовали это реализовать на практике? Основная проблема будет в управлении ключами. Необходимо будет создавать и сопроваждать инфраструктуру открытых ключей. У какждого метода есть свои плюсы и минусы. Тот же SRP может быть использован, в некоторых случаях, в качестве замены на мобильных устройствах.
                                                      +1
                                                      В теории действительно более безопасней. А вы пробовали это реализовать на практике?

                                                      К сожалению, да.

                                                      Основная проблема будет в управлении ключами. Необходимо будет создавать и сопроваждать инфраструктуру открытых ключей.

                                                      По вашему, сопровождать shared secret keys чем-то легче?
                                                        0
                                                        По вашему, сопровождать shared secret keys чем-то легче?

                                                        При симметричной криптографии всё можно засунуть в один сервер. А при безопасной реализайии ИВК, нужно отдельная инфраструктура со своими требованиями. Это не просто взяли сгенерировали кучу самоподписанных сертификатов и раздали их доверенным пользователям.
                                                          +1
                                                          Это не просто взяли сгенерировали кучу самоподписанных сертификатов и раздали их доверенным пользователям.

                                                          Почему? Это же зависит от конкретной задачи.
                                0
                                Так не надо сумму покупки на клиенте считать и всё) Делайте как все белые люди корзину от клиента максимум ИД товара и его количество. А то что вы предлагаете не имеет смысла в случае с формой т.к. вы браузеру сначала отдаёте функцию шифрования и всё ваша защита становится вашей уязвимостью…
              0
              Ну хорошо :)))

              По пункту номер 1:
              а) сбрутили идентификатор — начали гнать запросы.
              б и ц) будет работать, и будет достаточно секурно, если это сервер->сервер API взаимодействие.

              По пункту номер 2:

              Сценарий атаки:
              Есть интернет-магазин «Ромашка» и банк «Рога и Копыта», который оказывает услуги интернет-эквайринга для Ромашки. На странице чекаута на сайте Ромашки есть форма с hidden-полями: merchant_id, order_id, amount, description. Форма сабмитится на URL банка. Лжепокупатель может изменить order_id или amount и оплатить совсем другой счет и более того — на другую сумму.

              Способ защиты:
              Передавать еще и HMAC, проверка которого на стороне сервера не даст пользователю изменить данные в форме.
                0
                сбрутили идентификатор

                Сбрутить GUID? Вы серьезно? А что в этом случае мешает сбрутить секретный ключ для HMAC?

                будет работать, и будет достаточно секурно, если это сервер->сервер API взаимодействие.

                А если не сервер-сервер, то в чем отличие?

                Более того, почему вы считаете, что «сбрутить идентфикатор» можно, а «сбрутить идентификатор и пароль» нельзя?

                На странице чекаута на сайте Ромашки есть форма с hidden-полями: merchant_id, order_id, amount, description. Форма сабмитится на URL банка. Лжепокупатель может изменить order_id или amount и оплатить совсем другой счет и более того — на другую сумму.

                (а) кто является атакующим — пользователь или третья сторона? Если третья сторона, то каким образом она меняет данные?
                (б) зачем эта форма вообще показывается пользователю?
                  +1
                  Сбрутить GUID?
                  См выше про длину инентификатора.
                  (а) кто является атакующим — пользователь или третья сторона? Если третья сторона, то каким образом она меняет данные?
                  (б) зачем эта форма вообще показывается пользователю?

                  мне кажется, что я уже не раз ответил на все эти вопросы и мы идем на очередной круг.
                    0
                    См выше про длину инентификатора.

                    Где «выше»?

                    мне кажется, что я уже не раз ответил на все эти вопросы и мы идем на очередной круг.

                    Нет, вы нигде не отвечали на эти вопросы.
                      0
                      Читайте внимательно.
                        0
                        А если клиент — это форма в браузере пользователя, который может быть зловредным и изменит, скажем, сумму покупки, или идентификатор заказа, или еще какие-то данные, то без HMAC не обойтись

                        Вы вот это имеете в виду?
                0
                В остальном логика очень проста – собираем подпись, сравниваем регистронезависимо полученную подпись с подписью, переданной в данных.

                habrahabr.ru/post/181372, раздел «Аутентификация сообщений с помощью HMAC». Ну или security.stackexchange.com/a/74552.
                  0
                  Соль+алго с большей длиной хеша.
                    0
                    Соль вообще никак не влияет. А длина хэша… ну что ж, вы увеличили время подбора, да. Но вы не закрыли уязвимость.
                      0
                      Чтобы подобрать HMAC sha256 при помощи Timing attack придется отправить огромное количество запросов. Любая нормальная система заблокирует вас намного раньше чем вы успеете первые два символа подобрать :) Но это уже выходит за рамки текущего материала.
                        0
                        Система, описанная в вашем посте — заблокирует?
                          0
                          Обработка лимитов и алерты — это отдельная подсистема, не имеющая отношения к криптографии.
                          Правильно построенная система — да, заблокирует, если еще раньше не заблокирует WAF, не ограничит nginx по rate limit и т.п.
                            0
                            Вот поэтому решение, которое вы описываете в посте — уязвимо (и, собственно, является наглядной демонстрацией описанного по первой моей ссылке).

                            И при этом вы до сих пор не смогли показать, в каких случаях от него есть выгода.
                              0
                              Уязвимо в каком случае? Если можно безконтрольно брутить? Какое же решение в таком случае неуязвимо?
                                0
                                Уязвимо в каком случае? Если можно безконтрольно брутить? Какое же решение в таком случае неуязвимо?

                                Неуязвимых решений не бывает, бывают решения, которые уязвимы менее и более. Я вам указал на очевидную (и, в общем-то, сравнительно легко устранимую) уязвимость вашего. Просто что бы вы понимали: стоимость брутфорса вашего решения — k*n, решения, неподверженного тайминг-атаке — kn (где k — это временные затраты на перебор всех значений в одной позиции хэша, а n — количество позиций в хэше).
                                  0
                                  В теории — ОК. Но только я не понимаю, чем это решение более уязвимо, чем предложенные вами выше решение с "(а) просто идентификатором (б) идентификатором и паролем (ц) идентификатором и хэшом от пароля + nonce"
                                    0
                                    Ничем. Вопрос в том, зачем оно нужно вообще (в смысле, от какой атаки защищает).
                                    +1
                                    Для рассматриваемого случая необходимо выполнить минимум 1024*256*256= 226 запросов. Пусть один запрос равен 1 КБ, тогда вам необходимо передать 65 ГБ информации к серверу (столько же на получение), чтобы вычислить HMAC для одного фиксированного сообщения на основе атаки по времени.

                                    Вы можете сами расчитать вероятность того, что ни однин слой безопасности вас не отфильтрует (примеры). К тому же в нормальных приложениях используется метка времени, что даёт дополнительную защищаету от данной атаки.
                                      0
                                      Откуда вы взяли 1024*256*256?

                                      Метка времени — это хорошо, но в данном случае ее нет.

                                      (Я правильно понимаю, что вы считаете тайминг-атаку пренебрежимой опасностью?)
                                        +1
                                        Опять же возвращаемся к статье:
                                        Шум от задержек можно сглаживать двумя способами: ...


                                        Предположения:
                                        • 1024 — количество запросов;
                                        • 256 — количество символов в байте;
                                        • 256 — количество байт в хэш-значении.


                                        Метка времени — это хорошо, но в данном случае ее нет.

                                        Автор описывает метод аутентификации данных (с заголовком статьи я не согласен), а не их хранение или формат. Поэтому комментарий не уместен.

                                        (Я правильно понимаю, что вы считаете тайминг-атаку пренебрежимой опасностью?)

                                        Я считаю атаку по времени ещё одним видом атаки, от которой существуют свои методы защиты.
                                          0
                                          Автор описывает метод аутентификации данных (с заголовком статьи я не согласен), а не их хранение или формат. Поэтому комментарий не уместен.

                                          Как-то нелогично.

                                          Если описывается метод, то это одно (и надо оговаривать его ограничения).
                                          Если описывается реализация, то это другое (и надо учиться видеть ее ошибки).
                                          Наконец, если описывается система, то это третье.

                                          Я считаю атаку по времени ещё одним видом атаки, от которой существуют свои методы защиты.

                                          Из которых самый простой — это просто закрыть дырку (не отдавать зависимое от времеи сравнение).
                                            +1
                                            Приведу цитату из всё той же статьи:
                                            Выглядит вполне безопасно, так ведь? Вы уверены?

                                            Я сомневаюсь. Это уже предел моих знаний о потенциальных векторах атак на схемы такого типа. Но я не уверен, что нет способа взломать и это.


                                            Из которых самый простой — это просто закрыть дырку (не отдавать зависимое от времеи сравнение).

                                            Вы знаете более безопасный метод, реализующий тот же самы функционал, чем описано в статье?
                                              0
                                              Вы имеете в виду — более безопасный, чем HMAC, или более безопасный, чем та реализация HMAC, которая описана в посте?

                                                +1
                                                Чем реализация в статье плоха, с точки зрения ИБ, если не принемать во внимание атаку по времени?
                                                  +1
                                                  (Ордеринг ключей уже указали)

                                                  Я других проблем не вижу, но это не означает автоматически, что их нет. У меня изначально больше претензий было к концепции (области применения), чем к реализации.
                    0
                    Любые системы безопасности, основанные на том что взломщик не может никак узнать общий ключ «просто потому что» — уязвимы.
                      +1
                      Единственное применение — server-to-server over https, стоит по-моему упомянуть в статье что это не клиентская методика
                        0
                        HMAC много где используется (многие API многих сервисов, включая api вонтакте), ключ знает только сервис и апи-клиент, слово общий здесь некорректно. Почитайте как это сделано у амазона docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/HMACAuth.html

                        пока писал коммент, вы написали еще один — да, это совсем не для браузерного клиентсайда.
                          0
                          Timestamp в параметрах — хорошо.
                        0
                        Первое правило криптографии — нельзя изобретать велосипеды в области криптографии.
                        Если у вас HTTPS и взаимодействие сервер-сервер, то, censored, почему вы не используете https с двусторонней проверкой сертификатов?
                        Пусть даже самоподписанных.
                        Для банк-клиента в «сферическом банке в вакууме» нужно не просто сгенерировать личный ключ и предоставить его банку, нужно, блин, распечатать его в шестнадцатеричном виде на бумаге в двух экземплярах, подписать, поставить печать и принести в банк лично — и только после этого банк-клиент заработает. Почему для того же самого, по сути, банк-клиента, только в виде модуля для CMS (то есть полностью автоматизированного и работающего в заведомо контролируемом третьей стороной (хостером) окружении), вы делаете кривой велосипед?
                        Потому что так принято «у больших», которые до сих пор пишут онл@йн через собаку?
                          0
                          Не могу говорить за всех, но HMAC тем не менее используется почти во всех API банков и платежных систем, которые мне доводилось встречать, а подключал я их очень много. Лишь у одного была проверка клиентского сертификата. И хоть убейте, я не считаю это решение практически уязвимым, брут хеша — это очень теоретическая уязвимость. На практике, после 10 неудачных попыток, любая нормальная система Ваш ip заблокирует, а инцидентом будет заниматься служба ИБ.
                          0
                          Было бы намного логичнее согласовывать данные платежа с банком напрямую, а в форму вставлять только какой-нибудь идентификатор транзакции. К тому же вам, по сути, нужно подписать данные, которые уходят только в одном направлении, а для этого можно использовать цифровую подпись, а не MAC. Плюсы очевидны: одна точка отказа вместо нескольких. А вот для подписи cookies такой MAC отлично бы подошёл.
                            0
                            Такие решения тоже бывают. Я вообще считаю что все взаимодействие должно происходить сервер-сервер, а пользователю должен выдаваться URL для перенаправления. Но существуют разные решения, и решение с формой и HMAC весьма популярно и много где встречается.
                              0
                              А форма при этом обязательно размещена на HTTPS?
                                0
                                См выше — HTTPS мы подразумеваем по-умолчанию.
                                  0
                                  Вы-то — да (и именно поэтому такое количество вопросов возникает). А банки, которые интегрируются описанным способом?
                                    0
                                    Да, во всех таких реализациях, которые я видел, форма сабмитится на банковский URL всегда по HTTPS.
                                      +1
                                      Вопрос не только в том, куда форма сабмитится, но и в том (даже больше в том), как она доставляется клиенту.
                                        0
                                        Ну если учитывать, что клиентская сторона это в большинстве случаев страница чекаута в интернет-магазине, там скорее всего обычный HTTP, но я все же немного не улавливаю суть вопроса, на что это влияет, если форма в любом случае доступна пользователю браузера.
                                          +1
                                          Это влияет на количество потенциальных атакующих сторон.

                                          Если у вас страница чекаута доставляется по HTTP (буууу), то ее можно как угодно подменить в полете. А дальше мы прекрасно имеем атаку класса «возьми payload+HMAC от нужного нам заказа, сформируй страницу подтверждения с данными заказа жертвы, отправь на оплату нужного нам заказа». И как HMAC от этого защитит?

                                          Я же не зря у вас спрашиваю, кто является атакующей стороной. Когда у вас HTTPS, их (сторон), условно, три: пользователь, браузер (зловредный или скомпроментированный), третья сторона с помощью уязвимости сайта (например CSRF). Когда у вас HTTP, сторон немедленно становится на одну больше.
                                            0
                                            Теперь я понял о чем вы. Безусловно, это так. И именно поэтому в наших решениях HTTPS используется абсолютно везде по-умолчанию, а HMAC/CSRF-токены (+ лимиты соединений) реализуют дополнительный слой для аутентификации и контроля логической целостности сообщений.
                                              +1
                                              Я же не ленивый, я еще раз спрошу: от какой конкретно атаки и от кого вас защищает HMAC? (CSRF из рассмотрения исключаем, там HMAC — это всего лишь один из вариантов построения защиты, и не самый сильный)
                                                0
                                                Я тоже не ленивый, еще раз отвечу — от изменения пользователем данных формы. Разумеется, при условии, что контролируются лимиты.
                                                  +1
                                                  То есть злоумышленник — пользователь. А сценарий у нас, насколько я помню, магазин и платежная система, между магазином и платежной системой нет предварительного обмена (т.е. платежная система принимает решение о том, что и куда оплачивать, на основании данных, приходящих с формы).

                                                  Вот вы доставили пользователю форму, в которой есть payload (идентификатор мерчанта, идентификатор заказа, сумма). Как он дальше может провести атаку? (я специально убрал HMAC, чтобы сделать возможной любую атаку подменой)
                                                    0
                                                    Вариантов масса, в зависимости от бизнес-логики интернет-магазина при обработке Result от платежной системы. Если интернет-магазин проверяет на Result только ID заказа и не проверяет сумму — вектор очевиден.
                                                      +1
                                                      Ну так очевидно же, что проверять только идентификатор заказа — заведомая ошибка, и даже не только с точки зрения безопасности, но и с точки зрения бизнес-логики (платежные системы тоже ошибаются).
                                                        0
                                                        Нам с вами очевидно — мерчанту далеко не всегда. Я сам лично неоднократно встречал такие векторы и успешно их эксплуатировал.
                                                          0
                                                          В этом случае нужно исправлять эту ошибку, а не на форме добавлять контроль. Еще варианты?
                                                            0
                                                            Контроль на форме, навязанный платежной системой, как минимум, может защитить клиента-мерчанта от таких детских векторов, которым они, увы, зачастую подвержены.
                                                              0
                                                              Платежная система может навязать и проверку суммы платежа, вообще-то.

                                                              Но, как видите, проблема, которую вы в данном случае пытаетесь решить — не технологическая, а организационная.
                                                                0
                                                                … и да, если бы платежная система требовала предварительной передачи всех данных отдельной операцией, этой проблемы вообще бы не возникло. Это если со стороны платежной системы смотреть.
                              0
                              Предположим, мы хотим отправить какие-то данные другому человеку, при этом, и нам и получателю важно убедиться, что данные не будут изменены в процессе передачи.


                              Очень странное предположение. Вроде описана задача контроля целостности данных, а решение приводится для задач, традиционно решаемых с помощью механизмов ЭЦП, которые решают несколько больше задач, чем просто контроль целостности, а именно:
                              — невозможность отказа от авторства, с одной стороны
                              — доказательство авторства, с другой.

                              При этом описан механизм, похожий на ЭЦП с использованием известного обеим сторонам ключа, который эти дополнительные задачи не решает:
                              — автор сообщения не может доказать, что он сообщения не писал, если ему предоставляют сообщение, подписанное общим ключом
                              — автор сообщения не может доказать что сообщение писал именно он, поскольку ключ известен обеим сторонам.

                              По сути решена задача контроля целостности архива сообщений, типа удостоверения что с этими сообщениями «я» ознакомлен и они с тех пор не изменялись, где «я» включает отправителя и получателя без разделения, поскольку нет секретной информации известной только получателю или только отправителю.

                                0
                                Да, действительно в теории так и есть. Но что же происходит в реальной жизни?

                                Оказывается, что банк является и сервером и центром сертификации в одном лице. Это приводит к тому, что, на практике, нет разницы система с открытым клюм или симметричная с меткой времени, так как секретный ключ пользователя известен банку при генерации пары открытый/секретный ключ.
                                0
                                HMAC хорош главным образом своей скоростью. Вся криптография на открытых-закрытых ключах это довольно медленно, в сравнение с быстрым SHA2-хешем.

                                Ещё хорошее применение для HMAC — хранение сессионных данных в cookie, например id залогиненного пользователя. Конечно эти данные не должны быть секретными. Из плюсов по сравнению с серверной сессией: проще масштабировать.
                                  0
                                  JSON нельзя использовать для сериализации в подобных целях — он не гарантирует порядок сортировки полей в объекте (http://json.org/) Всё зависит от реализации библиотеки для конкретного языка.
                                    0
                                    Прочитайте статью внимательнее, там специально делается рекурсивная сортировка массива по ключам перед сериализацией в JSON и функция для этого написана.
                                      +1
                                      Я прочитал достаточно внимательно. Вы пишете:
                                      Почему именно JSON а не простой serialize PHP? Выбор в пользу JSON упал не случайно, поскольку это очень популярный формат сериализации, с которым будет легко работать не только в PHP, но и в любых других популярных языках программирования, таких как Java. Наша реализация должна быть предельно легко переносима на другие платформы и с использованием JSON-сериализации это будет сделать проще всего.

                                      То что вы сортируете массив по ключам перед кодировкой его в JSON, ровно никак не гарантирует вам то что в JSON-е они буду иметь тотже порядок, вот выдержка из спецификации:
                                      An object is an unordered set of name/value pairs.

                                      Другими словами, hash полученный Вами в PHP и, например, в Java теоретически может отличаться, несмотря на одинаковую сортировку ключей перед кодированием в JSON.
                                        0
                                        Хм, интересно, на практике все работало нормально, нужно будет провести больше тестов.
                                          0
                                          Простой пример, в последний версиях Chrome и FF
                                          JSON.stringify({a: 'a', 1: 1});
                                          {"1":1,"a":"a"}
                                          

                                          в PHP
                                          echo json_encode(['a' => 'a', 1 => 1]);
                                          {"a":"a","1":1}
                                          
                                            0
                                            Вы не думаете, что результат разный из-за разных ключей ('a' и a)?
                                              0
                                              А это не разные ключи, с точки зрения JSON они идентичны.

                                  Only users with full accounts can post comments. Log in, please.