hash

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

Хеширование

    Контрольная сумма файла (MD5): 2F19A5F13353769D7971BDD5434C92AF
		

Примеры хеш-функций:

CRC32
(Cyclic redundancy check - Циклический избыточный код) простая хэш функция разработанная для защиты данных от случайных изменений в компьютерных устройствах, таких как сетевые карты и жёсткие диски. CRC32 определяется международным стандартом CRC32-IEEE 802.3 Алгоритм очень быстр и, несмотря на полную криптографическую незащищённость, широко используется благодаря простоте реализации и скорости. 32-битный хэш-код обычно представляется шестнадцатеричным числом из 8 символов.
MD4
алгоритм хэширования, разработанный Рональдом Л. Ривестом из RSA Data Security, Inc. В настоящее время считается ненадёжным. Это быстрый алгоритм (на 32-битных процессорах) и его используют при вычислении хэшей в peer-to-peer сети EDonkey 2000. Алгоритм описан в RFC 1320. Хэш-код представляет шестнадцатеричное число из 32 символов.
MD5
ещё один алгоритм хэширования, разработанный Рональдом Л. Ривестом из RSA Data Security, Inc. Представляет улучшенную версию MD4. Алгоритм описан в RFC 1321. В течении многих лет MD5 был стандартом интернет, но сейчас считается сломанным. Хэш-код представляет шестнадцатеричное число из 32 символов.
SHA1
(Secure Hash Algorithm 1) алгоритм хэширования, разработанный NSA в 1993. Описан в RFC 3174. Он примерно в 2-3 раза медленнее алгоритма MD5. Хэш-код представляет шестнадцатеричное число длины 40.
Tiger
современная хэш-функция изобретённая Россом Андерсом и Эли Бихамом. Была специально придумана такой, чтобы быстро вычисляться на 64-битных процессорах. См. описание. Хэш-код представляет шестнадцатеричное число длины 48.
TTH
(Tiger Tree Hash) хэш, вычисляющийся в древовидной форме с использованием алгоритма Tiger. См. описание. TTH используется в нескольких peer-to-peer сетях: Direct Connect, Gnutella, Gnutella2, а также в таких программах как DC++, Phex и Shareaza. Хэш-код представляет base32-закодированную строку длины 39.
BTIH
(BitTorrent InfoHash) используется в p2p сети BitTorrent. Хэш-сумма зависит не только от данных, но и от имени файла и даже от программы вычисляющей хэш. RHash использует тот же метод, что и uTorrent. Хэш является строкой из 40 шестнадцатеричных чисел.
EDonkey 2000
один из самых быстрых алгоритмов хэширования. Он основан на устаревшем MD4 и используется в p2p сети EDonkey. Описание алгоритма: EDonkey network. Хэш-код представляет шестнадцатеричное число из 32 символов.
AICH
(Advanced Intelligent Corruption Handler) хэш, вычисляющийся в древовидной форме с использованием алгоритма SHA1. См. описание. Хэш используется в p2p сети EDonkey и обычно включается в EDonkey-линки. Хэш-код представляет base32-закодированную строку длиной в 32 символа.
WHIRLPOOL
хэш функция, рекоммендованная проектом NESSIE и принятая как ISO/IEC 10118-3:2004 международный стандарт. Хэш представляется 128-цифровым шестнадцатеричным числом.
GOST
хэш-функция определённая в российском государственном стандарте ГОСТ Р 34.11-94. Существует две широко распространённые версии алгоритма - с «тестовым» и CryptoPro наборами параметров. Хэш функция медленнее аналогичных, но используется для цифровой подписи в российских государственных банках и предприятиях. Хэш представляет шестнадцатеричную строку длины 64.
HAS-160
корейская хэш-сумма, разработанная для корейского алгоритма цифровой подписи (KCDSA). Хэш представляет шестнадцатеричную строку длины 40.
RIPEMD-160
(RACE Integrity Primitives Evaluation Message Digest) - 160-битная хэш-функция. Спецификация: веб-страница RIPEMD-160. Хэш представляет шестнадцатеричную строку длины 40.
EDON-R
семейство хэш-функций с произвольной длиной хэша. RHash поддерживает 256-битный и 512-битный варианты. 512-битный EDON-R является одним из самых быстрых алгоритмов на 64-битных процессорах. Хэш функция описана в статье: D. Gligoroski, S. Markovski, L. Kocarev Edon-R, An Infinite Family of Cryptographic Hash Functions (2006). 256-битный и 512-битный хэши представляют строку длиной 64 и 128 шестнадцатеричных символов соответсвенно.
Snefru
хэш функция разработанная Ральфом Меркле в 1990 и названная в честь египетского фараона Sneferu. В настоящее время она считается сломанной, к тому же она значительно медленнее современных хэш функций. Хэш 128-битного и 256-битного Snefru представляется шестнадцатеричной строкой длины 32 и 64 символа соответственно.128-битного и 256-битного Snefru представляется шестнадцатеричной строкой длины 32 и 64 символа соответственно.
Это всего лишь часть из существующй хеш-функций.
Некоторые из приведённых функций уже являются устаревшими и не рекомндуются для использованию. К примеру GOST

Хеширование применяется в следующих случаях:

Хеш-фукнции поддерживаемые PHP →

Хранение логин/пароля в БД

Рассмотрим пример хранения пары логин/пароль. Первый вариант.

idusrpasswd

В качестве примера во втором варианте первичным ключом является логин, т.е. столбец usr.

usrpasswd
Выбор столбца в качестве первичного ключа остаётся за Вами.

Хранение пароля в открытом виде

Храним пароль как есть. Например, если ввели пароль "12345", то он так и сохранится. Минус в том, что при взломе БД злоумышленник получает все пароли в явном виде.

usrpasswd
userpassword
prof123456
petyqwerty
ТОП-100 паролей

Храним пароль в зашифрованном

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

Чтобы этого не произошло, пароль лучше хранить в зашифрованном виде, использовав, к пример, алгоритмы шифрования md5, sha1 и т.п.

Самая распространённая хэш функция это md5.
Применяя md5, Вы всегда будете получать в качестве результата строку размером 32 символа. Но эти символы будут в шестнадцатеричном виде. Вы можете помещать в функцию md5() строки и числа любой длины, но на выходе всегда будете получать результат в 32 символа.
    <?php
        // 5f4dcc3b5aa765d61d8327deb882cf99
        $h = md5("passowrd");
    ?>
				
usrpasswd
user5f4dcc3b5aa765d61d8327deb882cf99
profe10adc3949ba59abbe56e057f20f883e
petyd8578edf8458ce06fbc5bb76a58c5ca4
Но и тут не всё так просто. ПРОБЛЕМА №1 - Коллизия хеш-функции

Использование хэш-функций →

Использование коллизии

Коллизия хеш-функции возникает, когда она выдает одинаковый результат на разные входные данные. Конечно же, вероятность этого достаточно мала, и зависит от длины хэша. Однако устаревшая (но до сих пор иногда используемая) функция crc32 возвращает в качестве хэша 32-битное целое число. Т.е., чтобы подобрать пароль к такому хэшу, по теории вероятности нужно получить 2^32 = 4 294 967 296 различных хэшей. Даже на хостинге crc32 может работать примерно со скоростью 350 000 хешей в секунду(посчитайте сами сколько нужно секунд, чтобы взломать такой хэш).

Конечно же это не относится md5(128-битный хеш) и тем более sha1(160-битный хеш). Использовать их коллизию практически невозможно, хотя есть статья и ещё одна...

Представим что "плохой дядька" украл базу данных вместе с хэшированным паролем. У него не будет возможности преобразовать 323322056 обратно в "supersecretpassword", однако, благодаря простому скрипту он можем подобрать другой пароль, который в хэшированном виде будет точно такой же как и тот, который находится в базе.

К примеру для нашего пароля "supersecretpassword" найдётся строка "MTIxMjY5MTAwNg==" точно с таким же хешем.
    echo crc32("supersecretpassword"); 
    // 323322056
	
    echo crc32("MTIxMjY5MTAwNg=="); 
    // 323322056
				

Пример коллизии →

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

Рекомендую использовать алгоритмы линейки SHA(на данный момент практически заверщён переход от SHA-1 к стандартам версии SHA-2). SHA-2 - это семейство криптографических функций SHA224, SHA256, SHA384 и SHA512. SHA224 и SHA384 являются по сути аналогами SHA256 и SHA512 соответственно, только после расчета свертки часть информации в ней отбрасывается.

При использовании более стойких алгоритмы для хеширования, часто встает вопрос производительности. Действительно, некоторые алгоритмы потребляют больше ресурсов.
Пример скорости перебора хешей (единицы измерения — мегахэши в секунду, то есть количество ), полученных на карточке AMD Radeon 7990:
  • MD5: 16000 M/s
  • SHA-1: 5900 M/s
  • SHA256: 2050 M/s
  • SHA512: 220 M/s
И тут не всё так просто. ПРОБЛЕМА №2 - Радужная таблица

Радужная таблица

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

Рассмотрим ситуацию. У Вас есть хешированный пароль пользователя, и хранится он в таблице базы данных. Даже если злоумышленник получает доступ к нашей базе данных он не сможет определить исходный пароль. Но что если он сравнивает все хэшированные пароли друг с другом, и находит некоторые из них как быть?

user5f4dcc3b5aa765d61d8327deb882cf99
......
pety5f4dcc3b5aa765d61d8327deb882cf99

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

Решение состоит в использовании случайного числа при генерации хеша, называемым солью.

"Солим" пароль

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

    $salt = "f?*-Q@t03#6_z";
	
    echo sha1($salt . "password"); // 8da1a876eabe199515de1766b87a602a5d06d378
				

Использование "соли" →

Так для нашего примера применим соль.

usrpasswd
user8da1a876eabe199515de1766b87a602a5d06d378
prof3c9ced61cf158c57bff7cad5d72ae9ceb17e565a
pety58131ab13b4af6894bee5ea6b6999cd90c159239

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

Одним из решений может быть генерация уникальной соли для каждого пользователя

Уникальная соль

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

usrpasswdsalt
user6aa747272c7d077d0fd1672ae48ce99da25d981179761ed37949c576e91959ec}{@kE$
profa3910b3c32a672ea9ee70866bc144dcba715bc9172d44debb8482f42aad6d503#_абв78
pety08ad24df81e43e013c5cf85643b2a85aae67e2369d8140ed66d53c37bec25557~~$~~
Хеш-функция SHA256 + соль

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

    $salt = "}{@kE$";
	
    echo hash("sha256", $salt . "password");
    // 6aa747272c7d077d0fd1672ae48ce99da25d981179761ed37949c576e91959ec
				

Использование уникальной "соли" →

Встроенная функция hash

Генерировать уникальную соль можно различными способами от самописных функций до строенных в PHP.
Большинство функций хэширования разрабатывались, учитывая то, что они часто используются для расчёта контрольных сумм каких-то значений или файлов с проверкой целостности данных.
Казалось бы - чем быстрее отработает функция, тем лучше. Чем быстрее сгенерируется хэш, тем быстрее наш пользователь сможет зарегистрироваться и начать работать. Однако чем больше скорость хэширования, тем быстрее его сможет подобрать и хакер.
ПРОБЛЕМА №3 - Скорость хеширования

Принудительное замедление

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

Если в пароле используются символы в нижнем и верхнем регистрах и цифры, то общее количество возможных символов составит 62 (26+26+10).

Для пароля длиной в 8 символов, существует 62^8 различных комбинаций (порядка 218 триллионов). Со скоростью в 1 миллиард хэшей в секунду (достаточно маленькая для брутфорс-атаки), пароль будет сломан примерно за 60 часов. А для наиболее распространенной длины пароля в 6 символов, длительность расшифровки составит меньше двух минут.

Лучше использовать более медленные функции хэширования или например можно замедлить функцию хэша вручную:

    function myhash($passwd, $salt) { 
	
        $hash = sha1($salt . $passwd);  
		
        // увеличиваем время выполнения функции на 1с
        sleep(1);  
		
        return $hash;  
    }
				
Используя ее, вместо 60 часов, хакер будет ломать 8-символьный пароль около 7 лет.