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. Можете форкать и дорабатывать класс на свое усмотрение, комментарии и предложения приветствуются.

Комментарии (101)


  1. lair
    11.07.2015 20:59

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

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

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

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


    1. IvanIDSolutions Автор
      11.07.2015 21:03

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

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

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

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

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

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


      1. lair
        11.07.2015 21:06

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

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

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

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

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

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


        1. IvanIDSolutions Автор
          11.07.2015 22:23

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

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

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

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

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

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


      1. lair
        11.07.2015 21:14

        HTTPS шифрует данные, чтобы они не могли быть прочитаны.

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

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

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

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

        Что непрактичного в использовании HTTPS для гарантии целостности запросов?


        1. IvanIDSolutions Автор
          11.07.2015 22:25

          HTTPS мы подразумеваем по-умолчанию. HMAC не ставится в противовес или замену HTTPS, а как дополнительный механизм аутентификации и проверки консистентности данных на логическом, а не на транспортном уровне. Улавливаете разницу?


          1. lair
            11.07.2015 22:40

            Какой выигрыш вы получаете, используя HMAC в дополнение к HTTPS?


            1. IvanIDSolutions Автор
              11.07.2015 22:43

              Защита логики в формах — раз.
              Аутентификация и защита от изменения пользователем запросов в API, в частности, в платежных формах и платежных API — два.


              1. lair
                11.07.2015 22:45

                Можете наглядно показать на примерах? Я вас не понимаю иначе.

                А то ведь для аутентификации в API достаточно просто передать свой идентификатор, зачем HMAC-то поверх городить?


                1. IvanIDSolutions Автор
                  11.07.2015 22:48

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

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


                  1. lair
                    11.07.2015 22:50

                    Передавая просто идентификтор — мы не можем клиента аутентифицировать.

                    Почему?

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

                    Данные сформированы легитимным клиентом — это та же самая аутентификация, см. выше.
                    Какие данные не были изменены и с какого момента?


                    1. IvanIDSolutions Автор
                      11.07.2015 22:53

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


                      1. lair
                        11.07.2015 22:56
                        +1

                        Давайте мы не будем путать две разные вещи, а?

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

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

                        (2) пожалуйста, опишите пошагово сценарий атаки, от которого вы пытаетесь защититься с помощью использования HMAC по форме (и сам способ защиты).


                        1. okazymyrov
                          20.07.2015 09:17

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


                          1. lair
                            20.07.2015 09:18

                            А причем тут sha-2? Мой вопрос был про работу поверх https.


                            1. okazymyrov
                              20.07.2015 09:37

                              Вопрос начинался с

                              в чем выигрыш от использования HMAC (по сравнению ...


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


                              1. lair
                                20.07.2015 09:40

                                Эээ, кем предполагается?

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


                                1. okazymyrov
                                  20.07.2015 09:57

                                  Эээ, кем предполагается?

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

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

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


                                  1. lair
                                    20.07.2015 11:32

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

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

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

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

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

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

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

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


                                    1. okazymyrov
                                      20.07.2015 12:06

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

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

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


                                      1. lair
                                        20.07.2015 12:12

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

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

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

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

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

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


                                        1. okazymyrov
                                          20.07.2015 12:39

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

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

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


                                          1. lair
                                            20.07.2015 13:19

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

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

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

                                            Ну, например, можно целиком все сообщение подписывать ЭЦП, или вообще подписывать и шифровать.


                                            1. okazymyrov
                                              20.07.2015 14:21
                                              +1

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

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

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

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


                                              1. lair
                                                20.07.2015 14:22

                                                Я уже говорил: я привык рассматривать ситуацию «HTTPS скомпроментирован» как автоматическую компроментацию всего приложения, потому что в моем случае конфиденциальность информации превыше всего.

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


                                                1. IvanIDSolutions Автор
                                                  20.07.2015 14:25

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


                                                  1. lair
                                                    20.07.2015 14:28

                                                    (Пойдем по кругу?)

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

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


                                                1. okazymyrov
                                                  20.07.2015 14:40

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

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

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

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


                                                  1. lair
                                                    20.07.2015 14:45

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

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

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

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


                                                    1. okazymyrov
                                                      20.07.2015 14:55
                                                      +1

                                                      Я говорю про свой конкретный сценарий.

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

                                                      Конкретно в сфере финансов — такой подход оправдан.


                                                      1. lair
                                                        20.07.2015 14:56

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


                                                        1. okazymyrov
                                                          20.07.2015 15:56

                                                          Ну тогда вы уже ответили на вопрос в своём комментарии. Всё зависит от того где и как использовать, и от входных данных конечно же.


                                                          1. lair
                                                            20.07.2015 15:57

                                                            Вот мне и интересен круг задач, в которых HMAC применим. Я свои два примера, где я считаю его оправданным, привел.


                                                            1. okazymyrov
                                                              20.07.2015 23:06
                                                              +1

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

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

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

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


                                                              1. lair
                                                                20.07.2015 23:11

                                                                В этом сценарии, конечно, есть уйма сомнительных мест (самое дикое из которых — отсутствие certificate pinning), но я вас услышал.


                                            1. okazymyrov
                                              20.07.2015 14:29

                                              Ну, например, можно целиком все сообщение подписывать ЭЦП, или вообще подписывать и шифровать.

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


                                              1. lair
                                                20.07.2015 14:32
                                                +1

                                                В теории действительно более безопасней. А вы пробовали это реализовать на практике?

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

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

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


                                                1. okazymyrov
                                                  20.07.2015 14:45

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

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


                                                  1. lair
                                                    20.07.2015 14:46
                                                    +1

                                                    Это не просто взяли сгенерировали кучу самоподписанных сертификатов и раздали их доверенным пользователям.

                                                    Почему? Это же зависит от конкретной задачи.


                      1. webportal
                        12.07.2015 10:52

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


  1. IvanIDSolutions Автор
    11.07.2015 23:05

    Ну хорошо :)))

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

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

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

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


    1. lair
      11.07.2015 23:12

      сбрутили идентификатор

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

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

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

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

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

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


      1. IvanIDSolutions Автор
        12.07.2015 00:01
        +1

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

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


        1. lair
          12.07.2015 00:04

          См выше про длину инентификатора.

          Где «выше»?

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

          Нет, вы нигде не отвечали на эти вопросы.


          1. IvanIDSolutions Автор
            12.07.2015 10:40

            Читайте внимательно.


            1. lair
              12.07.2015 11:09

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

              Вы вот это имеете в виду?


  1. lair
    11.07.2015 23:35

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

    habrahabr.ru/post/181372, раздел «Аутентификация сообщений с помощью HMAC». Ну или security.stackexchange.com/a/74552.


    1. IvanIDSolutions Автор
      12.07.2015 00:01

      Соль+алго с большей длиной хеша.


      1. lair
        12.07.2015 00:05

        Соль вообще никак не влияет. А длина хэша… ну что ж, вы увеличили время подбора, да. Но вы не закрыли уязвимость.


        1. IvanIDSolutions Автор
          12.07.2015 00:16

          Чтобы подобрать HMAC sha256 при помощи Timing attack придется отправить огромное количество запросов. Любая нормальная система заблокирует вас намного раньше чем вы успеете первые два символа подобрать :) Но это уже выходит за рамки текущего материала.


          1. lair
            12.07.2015 00:20

            Система, описанная в вашем посте — заблокирует?


            1. IvanIDSolutions Автор
              12.07.2015 00:22

              Обработка лимитов и алерты — это отдельная подсистема, не имеющая отношения к криптографии.
              Правильно построенная система — да, заблокирует, если еще раньше не заблокирует WAF, не ограничит nginx по rate limit и т.п.


              1. lair
                12.07.2015 00:24

                Вот поэтому решение, которое вы описываете в посте — уязвимо (и, собственно, является наглядной демонстрацией описанного по первой моей ссылке).

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


                1. IvanIDSolutions Автор
                  12.07.2015 00:27

                  Уязвимо в каком случае? Если можно безконтрольно брутить? Какое же решение в таком случае неуязвимо?


                  1. lair
                    12.07.2015 00:34

                    Уязвимо в каком случае? Если можно безконтрольно брутить? Какое же решение в таком случае неуязвимо?

                    Неуязвимых решений не бывает, бывают решения, которые уязвимы менее и более. Я вам указал на очевидную (и, в общем-то, сравнительно легко устранимую) уязвимость вашего. Просто что бы вы понимали: стоимость брутфорса вашего решения — k*n, решения, неподверженного тайминг-атаке — kn (где k — это временные затраты на перебор всех значений в одной позиции хэша, а n — количество позиций в хэше).


                    1. IvanIDSolutions Автор
                      12.07.2015 11:18

                      В теории — ОК. Но только я не понимаю, чем это решение более уязвимо, чем предложенные вами выше решение с "(а) просто идентификатором (б) идентификатором и паролем (ц) идентификатором и хэшом от пароля + nonce"


                      1. lair
                        12.07.2015 11:19

                        Ничем. Вопрос в том, зачем оно нужно вообще (в смысле, от какой атаки защищает).


                    1. okazymyrov
                      20.07.2015 09:33
                      +1

                      Для рассматриваемого случая необходимо выполнить минимум 1024*256*256= 226 запросов. Пусть один запрос равен 1 КБ, тогда вам необходимо передать 65 ГБ информации к серверу (столько же на получение), чтобы вычислить HMAC для одного фиксированного сообщения на основе атаки по времени.

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


                      1. lair
                        20.07.2015 09:38

                        Откуда вы взяли 1024*256*256?

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

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


                        1. okazymyrov
                          20.07.2015 09:49
                          +1

                          Опять же возвращаемся к статье:

                          Шум от задержек можно сглаживать двумя способами: ...


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


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

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

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

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


                          1. lair
                            20.07.2015 11:18

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

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

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

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

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


                            1. okazymyrov
                              20.07.2015 11:26
                              +1

                              Приведу цитату из всё той же статьи:

                              Выглядит вполне безопасно, так ведь? Вы уверены?

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


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

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


                              1. lair
                                20.07.2015 11:33

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


                                1. okazymyrov
                                  20.07.2015 12:46
                                  +1

                                  Чем реализация в статье плоха, с точки зрения ИБ, если не принемать во внимание атаку по времени?


                                  1. lair
                                    20.07.2015 13:20
                                    +1

                                    (Ордеринг ключей уже указали)

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


  1. MaximChistov
    11.07.2015 23:54

    Любые системы безопасности, основанные на том что взломщик не может никак узнать общий ключ «просто потому что» — уязвимы.


    1. MaximChistov
      12.07.2015 00:21
      +1

      Единственное применение — server-to-server over https, стоит по-моему упомянуть в статье что это не клиентская методика


    1. AlexGx
      12.07.2015 00:25

      HMAC много где используется (многие API многих сервисов, включая api вонтакте), ключ знает только сервис и апи-клиент, слово общий здесь некорректно. Почитайте как это сделано у амазона docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/HMACAuth.html

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


      1. IvanIDSolutions Автор
        12.07.2015 11:19

        Timestamp в параметрах — хорошо.


  1. vanxant
    12.07.2015 00:32

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


    1. IvanIDSolutions Автор
      12.07.2015 10:31

      Не могу говорить за всех, но HMAC тем не менее используется почти во всех API банков и платежных систем, которые мне доводилось встречать, а подключал я их очень много. Лишь у одного была проверка клиентского сертификата. И хоть убейте, я не считаю это решение практически уязвимым, брут хеша — это очень теоретическая уязвимость. На практике, после 10 неудачных попыток, любая нормальная система Ваш ip заблокирует, а инцидентом будет заниматься служба ИБ.


  1. Disasm
    12.07.2015 02:02

    Было бы намного логичнее согласовывать данные платежа с банком напрямую, а в форму вставлять только какой-нибудь идентификатор транзакции. К тому же вам, по сути, нужно подписать данные, которые уходят только в одном направлении, а для этого можно использовать цифровую подпись, а не MAC. Плюсы очевидны: одна точка отказа вместо нескольких. А вот для подписи cookies такой MAC отлично бы подошёл.


    1. IvanIDSolutions Автор
      12.07.2015 11:21

      Такие решения тоже бывают. Я вообще считаю что все взаимодействие должно происходить сервер-сервер, а пользователю должен выдаваться URL для перенаправления. Но существуют разные решения, и решение с формой и HMAC весьма популярно и много где встречается.


      1. lair
        12.07.2015 11:31

        А форма при этом обязательно размещена на HTTPS?


        1. IvanIDSolutions Автор
          12.07.2015 11:31

          См выше — HTTPS мы подразумеваем по-умолчанию.


          1. lair
            12.07.2015 11:32

            Вы-то — да (и именно поэтому такое количество вопросов возникает). А банки, которые интегрируются описанным способом?


            1. IvanIDSolutions Автор
              12.07.2015 11:34

              Да, во всех таких реализациях, которые я видел, форма сабмитится на банковский URL всегда по HTTPS.


              1. lair
                12.07.2015 11:35
                +1

                Вопрос не только в том, куда форма сабмитится, но и в том (даже больше в том), как она доставляется клиенту.


                1. IvanIDSolutions Автор
                  12.07.2015 11:40

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


                  1. lair
                    12.07.2015 11:44
                    +1

                    Это влияет на количество потенциальных атакующих сторон.

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

                    Я же не зря у вас спрашиваю, кто является атакующей стороной. Когда у вас HTTPS, их (сторон), условно, три: пользователь, браузер (зловредный или скомпроментированный), третья сторона с помощью уязвимости сайта (например CSRF). Когда у вас HTTP, сторон немедленно становится на одну больше.


                    1. IvanIDSolutions Автор
                      12.07.2015 11:48

                      Теперь я понял о чем вы. Безусловно, это так. И именно поэтому в наших решениях HTTPS используется абсолютно везде по-умолчанию, а HMAC/CSRF-токены (+ лимиты соединений) реализуют дополнительный слой для аутентификации и контроля логической целостности сообщений.


                      1. lair
                        12.07.2015 11:50
                        +1

                        Я же не ленивый, я еще раз спрошу: от какой конкретно атаки и от кого вас защищает HMAC? (CSRF из рассмотрения исключаем, там HMAC — это всего лишь один из вариантов построения защиты, и не самый сильный)


                        1. IvanIDSolutions Автор
                          12.07.2015 11:52

                          Я тоже не ленивый, еще раз отвечу — от изменения пользователем данных формы. Разумеется, при условии, что контролируются лимиты.


                          1. lair
                            12.07.2015 11:58
                            +1

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

                            Вот вы доставили пользователю форму, в которой есть payload (идентификатор мерчанта, идентификатор заказа, сумма). Как он дальше может провести атаку? (я специально убрал HMAC, чтобы сделать возможной любую атаку подменой)


                            1. IvanIDSolutions Автор
                              12.07.2015 12:02

                              Вариантов масса, в зависимости от бизнес-логики интернет-магазина при обработке Result от платежной системы. Если интернет-магазин проверяет на Result только ID заказа и не проверяет сумму — вектор очевиден.


                              1. lair
                                12.07.2015 12:06
                                +1

                                Ну так очевидно же, что проверять только идентификатор заказа — заведомая ошибка, и даже не только с точки зрения безопасности, но и с точки зрения бизнес-логики (платежные системы тоже ошибаются).


                                1. IvanIDSolutions Автор
                                  12.07.2015 12:07

                                  Нам с вами очевидно — мерчанту далеко не всегда. Я сам лично неоднократно встречал такие векторы и успешно их эксплуатировал.


                                  1. lair
                                    12.07.2015 12:10

                                    В этом случае нужно исправлять эту ошибку, а не на форме добавлять контроль. Еще варианты?


                                    1. IvanIDSolutions Автор
                                      12.07.2015 12:12

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


                                      1. lair
                                        12.07.2015 12:28

                                        Платежная система может навязать и проверку суммы платежа, вообще-то.

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


                                      1. lair
                                        12.07.2015 12:33

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


  1. VolCh
    12.07.2015 12:48

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


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

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

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


    1. okazymyrov
      20.07.2015 08:44

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

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


  1. vsb
    12.07.2015 18:06

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

    Ещё хорошее применение для HMAC — хранение сессионных данных в cookie, например id залогиненного пользователя. Конечно эти данные не должны быть секретными. Из плюсов по сравнению с серверной сессией: проще масштабировать.


  1. volovikov
    12.07.2015 18:54

    JSON нельзя использовать для сериализации в подобных целях — он не гарантирует порядок сортировки полей в объекте (http://json.org/) Всё зависит от реализации библиотеки для конкретного языка.


    1. IvanIDSolutions Автор
      12.07.2015 19:25

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


      1. volovikov
        12.07.2015 19:42
        +1

        Я прочитал достаточно внимательно. Вы пишете:

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

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

        Другими словами, hash полученный Вами в PHP и, например, в Java теоретически может отличаться, несмотря на одинаковую сортировку ключей перед кодированием в JSON.


        1. IvanIDSolutions Автор
          12.07.2015 20:02

          Хм, интересно, на практике все работало нормально, нужно будет провести больше тестов.


          1. volovikov
            12.07.2015 20:31

            Простой пример, в последний версиях Chrome и FF

            JSON.stringify({a: 'a', 1: 1});
            {"1":1,"a":"a"}
            

            в PHP
            echo json_encode(['a' => 'a', 1 => 1]);
            {"a":"a","1":1}
            


            1. okazymyrov
              20.07.2015 08:37

              Вы не думаете, что результат разный из-за разных ключей ('a' и a)?


              1. lair
                20.07.2015 09:17

                А это не разные ключи, с точки зрения JSON они идентичны.