php что такое соль
Хеширование пароля на PHP
Давайте, например, найдем хеш какой-нибудь строки:
Сейчас нам необходимо переделать нашу регистрацию и нашу авторизацию. Для начала я бы советовал очистить таблицу с юзерами, так как там сейчас хранятся пароли в открытом виде, а должны хранится их хеши. Затем при тестировании регистрации таблица заполнится данными в новом формате.
Давайте теперь поправим нашу регистрацию так, чтобы при сохранении нового пользователя в базу добавлялся не пароль, а его хеш.
Описанная правка будет представлять собой что-то такое:
Внесем аналогичные правки в авторизацию:
Внесите изменения в регистрацию с учетом хеширования, зарегистрируйте пару новых пользователей, убедитесь, что в базу данных они добавились с хешированными паролями.
Внесите изменения в авторизацию с учетом хеширования, попробуйте авторизоваться под зарегистрированными ранее пользователями.
Добавляем соль в регистрацию
Речь идет о достаточно простых, популярных паролях.
Хеши достаточно сложных паролей таким образом не разгадать (попробуйте).
Можно, конечно, придумать более умный алгоритм проверки пароля на сложность, но есть другое решение.
То есть при регистрации вы будете делать что-то типа такого:
При этом соль будет разная для каждого пользователя, ее нужно будет генерировать случайным образом в момент регистрации.
Вот готовая функция, которая сделает это:
С помощью этой функции можно переписать наш код вот так:
Реализуйте описанную выше регистрацию с соленым паролем.
Добавляем соль в авторизацию
Теперь нам необходимо поменять авторизацию. Здесь уже изменения будут более существенными.
Уже не получится проверить правильность пары логин-пароль сразу же, одним запросом. Почему: потому что, чтобы проверить пароль, надо получить его соленый хеш, а соль хранится в базе данных и уникальная для каждого логина.
Давайте добавим проверку пароля:
Реализуйте описанную выше авторизацию с соленым паролем. Попробуйте зарегистрируйтесь, авторизуйтесь, убедитесь, что все работает.
Используем функцию password_hash
На самом деле функция md5 и соление пароля с ее помощью считается устаревшим. Мы изучали ее, чтобы вы поняли дальнейший материал, а также потому, что вы можете столкнуться с этим, работая с чужими проектами.
Попробуйте несколько раз запустите этот код:
Давайте посмотрим на примере:
То есть получится, что в базе данных в поле password мы будем хранить соленый пароль вместе с его солью. При этом хешированный пароль будет иметь большую длину. Поэтому в базе данных нам нужно исправить размер поля с паролем и установить ее в 60 символов.
Теперь давайте поправим код регистрации. Вот то, что есть сейчас:
С помощью password_hash мы сократим это до:
Аналогичным образом подправится код авторизации:
Переделайте вашу авторизацию и регистрацию на новые изученные функции.
В настоящее время алгоритмом по умолчанию будет алгоритм BCrypt (то есть аналог md5, но мощнее), который своим результатом возвращает строку соль+хеш размером 60 символов.
В таком случае изменения в вашем коде произойдут автоматически при переходе на новую версию PHP.
Безопасное хеширование паролей
В этом разделе разъясняются причины, стоящие за хешированием паролей в целях безопасности, а также эффективные методы хеширования.
Хеширование паролей является одним из самых основных соображений безопасности, которые необходимо сделать, при разработке приложения, принимающего пароли от пользователей. Без хеширования, пароли, хранящиеся в базе вашего приложения, могут быть украдены, например, если ваша база данных была скомпрометирована, а затем немедленно могут быть применены для компрометации не только вашего приложения, но и аккаунтов ваших пользователей на других сервисах, если они не используют уникальных паролей.
Применяя хеширующий алгоритм к пользовательским паролям перед сохранением их в своей базе данных, вы делаете невозможным разгадывание оригинального пароля для атакующего вашу базу данных, в то же время сохраняя возможность сравнения полученного хеша с оригинальным паролем.
Важно заметить, однако, что хеширование паролей защищает их только от компрометирования в вашем хранилище, но не обязательно от вмешательства вредоносного кода в вашем приложении.
Почему популярные хеширующие функции, такие как md5() и sha1() не подходят для паролей?
Такие хеширующие алгоритмы как MD5, SHA1 и SHA256 были спроектированы очень быстрыми и эффективными. При наличии современных технологий и оборудования, стало довольно просто выяснить результат этих алгоритмов методом «грубой силы» для определения оригинальных вводимых данных.
Из-за той скорости, с которой современные компьютеры могут «обратить» эти хеширующие алгоритмы, многие профессионалы компьютерной безопасности строго не рекомендуют использовать их для хеширования паролей.
Если популярные хеширующие функции не подходят, как же я тогда должен хешировать свои пароли?
При хешировании паролей существует два важных соображения: это стоимость вычисления и соль. Чем выше стоимость вычисления хеширующего алгоритма, тем больше времени требуется для взлома его вывода методом «грубой силы».
При хешировании паролей рекомендуется применять алгоритм Blowfish, который также используется по умолчанию в API хеширования паролей, так как он значительно большей вычислительной сложности, чем MD5 или SHA1, при этом по-прежнему гибок.
Учтите, что, если вы используете функцию crypt() для проверки пароля, то вам нужно предостеречь себя от атак по времени, применяя сравнение строк, которое занимает постоянное время. Ни операторы PHP == и ===, ни функция strcmp() не являются таковыми. Функция же password_verify() как раз делает то, что нужно. Настоятельно рекомендуется использовать встроенное API хеширования паролей, если есть такая возможность.
Что такое соль?
Криптографическая соль представляет собой данные, которые применяются в процессе хеширования для предотвращения возможности разгадать оригинальный ввод с помощью поиска результата хеширования в списке заранее вычисленных пар ввод-хеш, известном также как «радужная» таблица.
password_hash() создаёт случайную соль в случае, если она не была передана, и чаще всего это наилучший и безопасный выбор.
Как я должен хранить свою соль?
Солим пароли
Данная заметка призвана пролить свет на использование соли при хешировании пароля. Если посмотреть в комментарии к этому топику habrahabr.ru/post/145642, то возникает подозрение, что некоторые люди неправильно понимают предназначение соли. На примерах постараюсь показать, для чего используется этот механизм. Всех заинтересовавшихся прошу под кат.
Представим простую авторизацию. От пользователя к нам приходит связка значений логин/пароль, мы получаем хеш пароля и сравниваем данную связку с данными, хранящимися в базе. Для простоты будем использовать MD5 и примеры кода на PHP.
В данном случае, если у пользователя пароль qwerty, мы получим следующий хеш: d8578edf8458ce06fbc5bb76a58c5ca4. Если злоумышленник получит доступ к нашей базе, для подбора паролей он может воспользоваться уже готовыми сервисами(http://wordd.org/D8578EDF8458CE06FBC5BB76A58C5CA4), в которых уже есть значения, дающие данный хеш, либо сбрутить самому.
Для защиты от уже готовых таблиц хешей с значениями, можно использовать статическую соль:
Сейчас при том же пароле qwerty мы получим совершенно другой хеш bdadb0330124cda0e8499c9cd118f7bd. Готовые таблицы уже не помогут злоумышленнику, ему придется использовать брутфорс. Вот здесь и кроется минус статической соли: злоумышленник сможет сгенерировать свою таблицу хешей со статической солью и получить значения большинства паролей из базы. Для устранения этого минуса используется уникальная соль к каждому хешу:
Т.е. теперь помимо логина/хеша пароля в базе необходимо будет хранить значение сгенерированной соли для каждого пользователя. Разберем пример: у нас два пользователя: user1 и user2. Оба используют пароль qwerty. Но у первого была сгенерирована соль zxcv а у второго asdf. В итоге у пользователей при одинаковом пароле будут различные хеши: 1d8f3272b013387bbebcbedb4758586d и a192862aa3bf46dffb57b12bdcc4c199.Что это дает: теперь нельзя будет сгененерировать одну таблицу хешей, для нахождения значения хеша с динамической солью придется генерировать заново. Все это направлено на увеличение времени подбора значений в случае «слива» базы, при использовании «хороших» алгоритмов хеширования, на подбор хотя бы пары паролей уже может уйти значительное количество времени. Важно понимать, что генерируемая соль защищает не одного единственного пользователя, а всех вместе от массового брута. На этом все, хочу напомнить что используйте криптостойкие алгоритмы хеширования SHA1, SHA512. Используемый выше MD5 к использованию не желателен, т.к. признан устаревшим.
Хорошо резюмировал Kolonist в своем комментарии habrahabr.ru/post/145648/#comment_4894759 ( за что ему отдельное спасибо и плюс):
Еще раз.
1. Нет соли — используем уже готовые радужные таблицы.
2. Есть одна на всех соль — генерируем одну радужную таблицу и «ломаем» по ней всех пользователей.
3. Есть отдельная соль для каждого пользователя — отдельно брутфорсим каждого пользователя.
crypt
(PHP 4, PHP 5, PHP 7, PHP 8)
crypt — Необратимое хеширование строки
Эта функция (пока) небезопасна для обработки данных в двоичной форме!
Описание
crypt() возвращает хешированную строку, полученную с помощью стандартного алгоритма UNIX, основанного на DES или другого алгоритма.
Вид хеширования определяется переданным аргументом salt (соль). Если соль не указана, будет автоматически сгенерирована стандартная случайная двухсимвольная (DES) или двенадцатисимвольная (MD5) соль, в зависимости от доступности алгоритма MD5 в crypt(). Предопределённая константа CRYPT_SALT_LENGTH позволяет определить максимально доступную длину соли в соответствии с используемыми алгоритмами.
Поддерживаются следующие типы хешей:
Список параметров
Необязательный параметр с солью, на которой будет основано хеширование. Если не указан, поведение определяется по наличию реализованных алгоритмов в системе и может привести к неожиданным результатам.
Возвращаемые значения
Возвращает хешированную строку или строку короче 13 символов, гарантированно отличающуюся от соли в случае возникновения ошибки.
Список изменений
Примеры
Пример #1 Пример использования crypt()
// соль будет сгенерирована автоматически; не рекомендуется
$hashed_password = crypt ( ‘mypassword’ );
Пример #2 Использование crypt() и htpasswd
// пароль
$password = ‘mypassword’ ;
Пример #3 Использование crypt() с различными видами хешей
Результатом выполнения данного примера будет что-то подобное:
Примечания
Замечание: Функция расшифровки отсутствует, так как crypt() использует необратимый алгоритм хеширования.
Смотрите также
User Contributed Notes 8 notes
The #2 comment on this comments page (as of Feb 2015) is 9 years old and recommends phpass. I have independently security audited this product and, while it continues to be recommended for password security, it is actually insecure and should NOT be used. It hasn’t seen any updates in years (still at v0.3) and there are more recent alternatives such as using the newer built-in PHP password_hash() function that are much better. Everyone, please take a few moments to confirm what I’m saying is accurate (i.e. review the phpass code for yourself) and then click the down arrow to sink the phpass comment to the bottom. You’ll be increasing security across the Internet by doing so.
For those who want details: md5() with microtime() are a fallback position within the source code of phpass. Instead of terminating, it continues to execute code. The author’s intentions of trying to work everywhere are admirable but, when it comes to application security, that stance actually backfires. The only correct answer in a security context is to terminate the application rather than fallback to a weak position that can potentially be exploited (usually by forcing that weaker position to happen).
As I understand it, blowfish is generally seen a secure hashing algorithm, even for enterprise use (correct me if I’m wrong). Because of this, I created functions to create and check secure password hashes using this algorithm, and using the (also deemed cryptographically secure) openssl_random_pseudo_bytes function to generate the salt.
To generate salt use mcrypt_create_iv() not mt_rand() because no matter how many times you call mt_rand() it will only have at most 32 bits of entropy. Which you will start seeing salt collisions after about 2^16 users. mt_rand() is seeded poorly so it should happen sooner.
$2y$05$. J2ihDv8vVf7QZ9BsaRrKyqs2tkn55Yq
$2y$05$. O/jw2XygQa2.LrIT7CFCBQowLowDP6Y.
$2y$05$. eDOx4wMcy7WU.kE21W6nJfdMimsBE3V6
$2y$05$. uMMcgjnOELIa6oydRivPkiMrBG8.aFp.
Here is an expression to generate pseudorandom salt for the CRYPT_BLOWFISH hash type:
The salt created will be 128 bits in length, padded to 132 bits and then expressed in 22 base64 characters. (CRYPT_BLOWFISH only uses 128 bits for the salt, even though there are 132 bits in 22 base64 characters. If you examine the CRYPT_BLOWFISH input and output, you can see that it ignores the last four bits on input, and sets them to zero on output.)
Note that the high-order bits of the four 32-bit dwords returned by mt_rand() will always be zero (since mt_getrandmax == 2^31), so only 124 of the 128 bits will be pseudorandom. I found that acceptable for my application.
The crypt() function cant handle plus signs correctly. So if for example you are using crypt in a login function, use urlencode on the password first to make sure that the login procedure can handle any character:
steve at tobtu dot com was right 4 years ago, but now mcrypt_create_iv() (and bcrypt in general) is deprecated!
Use random_bytes() instead:
= base64_encode ( random_bytes ( 16 ));
If you’re stuck with CRYPT_EXT_DES, then you’ll want to pick a number of iterations: the 2nd-5th characters of the «salt».
My experimentation suggests that the 5th character is the most significant. A ‘.’ is a zero and ‘Z’ is the highest value. Using all dots will create an error: all passwords will be encrypted to the same value.
Here are some encryption timings (in seconds) that I obtained, with five different iteration counts over the same salt, and the same password, on a quad core 2.66GHz Intel Xeon machine.
_1111 time: 0.15666794776917
_J9.Z time: 1.8860530853271
_J9.. time: 0.00015401840209961
_. Z time: 1.9095730781555
_ZZZZ time: 1.9124970436096
_. A time: 0.61211705207825
I think a half a second is reasonable for an application, but for the back end authentication? I’m not so sure: there’s a significant risk of overloading the back end if we’re getting lots of authentication requests.
While the documentation says that crypt will fail for DES if the salt is invalid, this turns out to not be the case.
The crypt function will accept any string of two characters or more for DES as long as it doesn’t match the pattern for any other hashing schema. The remaining characters will be ignored.
«Соленое» хеширование паролей: делаем правильно
1. Введение
Если вы веб-разработчик, то, вероятно, должны были разрабатывать систему учетных записей пользователей. Самый важный аспект системы учетных записей это то, как защищены пароли пользователей.
Базы данных учетных записей пользователей часто взламываются, поэтому вы однозначно должны сделать что-то для защиты паролей ваших пользователей на случай, если ваш сайт будет взломан.
Самым лучшим способом защиты паролей является « соленое » хеширование пароля. И в этой статье объясняется, как сделать это должным образом.
Существует много противоречивых идей и заблуждений на счет того, как правильно осуществить хеширование пароля, вероятно, из-за изобилия неверной информации в Интернете.
Хеширование пароля – это один из тех предметов, которые очень просты по сути, но все еще много людей понимают его неверно. С помощью этой статьи я надеюсь объяснить вам не только, как правильно делать хеширование, но и почему оно должно быть сделано подобным образом.
2. Что такое хеширование пароля?
Хеш-алгоритмы являются односторонними функциями. Они превращают любое количество данных в « дактилоскопический отпечаток » фиксированной длины, который не может быть обратим.
Также эти алгоритмы имеют такое свойство, что если входное значение изменяется даже совсем немного, полученный хеш-код полностью отличается от исходного (смотрите пример выше).
Это отлично подходит для защиты паролей, потому что мы хотим сохранить пароли в зашифрованном виде, невозможном для расшифровки, и в то же время мы должны быть способны проверить то, что пароль пользователя корректен.
Общая схема процесса регистрации аккаунта и аутентификации в системе учетных записей, основанной на хешировании, выглядит следующим образом:
На шаге 4 никогда не сообщайте пользователю, что именно не так: имя пользователя или пароль. Всегда отображайте только общее сообщение, например, « Неверное имя пользователя или пароль ». Это не позволит злоумышленникам вычислить верные имена пользователей без знания их паролей.
Следует отметить, что хеш-функции, используемые для защиты паролей, это не те же хеш-функции, которые вы могли видеть на занятиях по структурам данных. Хеш-функции, используемые для реализации структур данных, таких как хеш-таблицы, разрабатываются для того, чтобы быть быстрыми, а не безопасными.
Легко подумать, что все, что вы должны сделать, это пропустить пароль через криптографическую хеш-функцию, и пароли ваших пользователей будут в безопасности. Это далеко от правды. Есть много видов атак, позволяющих очень быстро восстановить пароли из простых хеш-кодов.
Но существует несколько легко реализуемых техник, которые делают эти атаки гораздо менее эффективными. Чтобы обосновать необходимость применения этих методов, рассмотрим этот веб-сайт.
На главной странице вы можете отправить список хеш-кодов для взлома и получить результат менее чем за одну секунду. Очевидно, что простое хеширование пароля не соответствует нашим требованиям к безопасности.
В следующей секции мы обсудим некоторые распространенные виды атак, используемые для взлома простых хеш-кодов паролей.
3. Как взламывается хеш
Атаки полным перебором :
Самый простой способ взломать хеш-код – это попробовать угадать пароль, вычисляя хеш-код для каждого предположения и проверяя, совпадает ли этот хеш-код со взламываемым.
Если хеш-коды одинаковые, то предположенная комбинация является паролем. Двумя наиболее распространенными способами угадывания паролей является атаки по словарю и атаки полным перебором.
Атака по словарю использует файл, содержащий слова, фразы, распространенные пароли и другие строки, которые с некоторой вероятностью могут быть использованы в качестве пароля. Каждое слово в файле захешировано, и его хеш-код сравнивается с хеш-кодом пароля.
Если они совпадают, то данное слово является паролем. Такие файлы словарей построены путем извлечения слов из больших массивов текста и даже из реальных баз данных паролей. Часто применяется дополнительная обработка файлов словарей, например, замена слов « лит спик » эквивалентами (« hello » становится «h3110»), чтобы сделать их более эффективными.
Атака полным перебором пробует все возможные комбинации символов до заданной длины. Эти атаки требуют очень больших вычислительных затрат, и, как правило, они наименее эффективны по показателю число взломанных хеш-кодов на время выполнения, но они всегда в конечном счете находят пароль.
Пароли должны быть достаточной длины, чтобы поиск по всем возможным символьным строкам для его нахождения занимал слишком много времени, чтобы оправдывать себя.
Не существует методов предотвращения атак по словарю или атак полным перебором. Можно сделать их менее эффективными, но нет способа предотвратить их полностью. Если ваша система хеширования паролей безопасна, единственный способ взломать хеш-коды – это выполнить атаку по словарю или полным перебором для каждого хеш-кода.
Таблицы поиска
Таблицы поиска – это крайне эффективный метод для очень быстрого взлома большого количества хеш-кодов одного типа. Основная идея заключается в том, чтобы заранее вычислить хеш-коды паролей из словаря паролей, а затем сохранить хеш-коды и соответствующие им пароли в структуру данных типа таблица поиска.
Умело реализованные таблицы поиска могут обрабатывать сотни поисков хеш-кодов в секунду, даже если они содержат много миллиардов хеш-кодов.
Эти хеш-коды могут быть взломаны меньше чем за 1 секунду:
Вы можете сгенерировать собственный хеш-код вашего наиболее часто используемого пароля здесь и попробовать взломать его с помощью упомянутого выше инструмента.
Обратные таблицы поиска
Этот вид атаки позволяет злоумышленнику применить атаку по словарю или полным перебором ко многим хеш-кодам одновременно без наличия предварительно вычисленной таблицы поиска.
Сначала злоумышленник создает таблицу поиска, которая сопоставляет каждый хеш-код пароля из скомпрометированной базы данных пользовательских аккаунтов со списком пользователей, имевших этот хеш-код. Затем взломщик хеширует каждый предполагаемый пароль и использует таблицу поиска для получения списка пользователей, чей пароль был угадан взломщиком.
Этот вид атак особенно эффективен, потому что зачастую несколько пользователей имеют один и тот же пароль.
Радужные таблицы
Радужные таблицы – это техника, являющаяся компромиссом между временем поиска и занимаемой памятью. Они похожи на таблицы поиска, за исключением того, что они жертвуют скоростью взлома хеш-кодов, чтобы сделать таблицы поиска меньше.
Так как таблицы меньше, решения для большего количества хеш-кодов могут быть сохранены в том же объеме памяти, делая такие таблицы более эффективными. Существуют радужные таблицы, которые могут взломать любой md5 хеш-код пароля вплоть до 8 символов в длину.
Далее мы рассмотрим технику под названием « соление », которая делает невозможным использование радужных таблиц и таблиц поиска для взлома хеш-кодов.
4. Добавление соли
Радужные таблицы и таблицы поиска работают только потому, что каждый пароль хешируется совершенно одинаковым способом.
Если два пользователя имеют один и тот же пароль, у них будет совпадать и хеш-код пароля. Мы можем предотвратить эти атаки, внеся случайную составляющую в каждый хеш-код; таким образом, когда одинаковый пароль хешируется дважды, хеш-коды получаются разные.
Мы можем внести случайную составляющую в хеш-коды, добавив в конец или в начало пароля случайную строку, называемую « соль », перед операцией хеширования. При этом, как показано в примере выше, всякий раз получаются совершенно разные строки из одного и того же хеш-кода пароля.
Чтобы проверить, корректен ли пароль, нам нужна соль, поэтому обычно ее сохраняют в базе данных пользовательских аккаунтов вместе с хеш-кодом, или как часть самой строки хеш-кода.
Соль не обязательно держать в секрете. Просто при использовании случайной величины для построения хеш-кода таблицы поиска, обратные таблицы поиска и радужные таблицы становятся неэффективными. Злоумышленник не узнает заранее, какая будет соль, поэтому он не может предварительно вычислить таблицу поиска или радужную таблицу.
Если пароль каждого пользователя хешируется с помощью разной соли, атака с использованием обратной таблицы поиска также не будет работать.
В следующей секции мы рассмотрим распространенные ошибки при реализации соли.
НЕВЕРНЫЙ способ : короткая соль и повторное использование соли
Эта секция охватывает другое распространенное заблуждение насчет хеширования паролей: дурацкие комбинации хеш-алгоритмов. Очень легко увлечься и попытаться комбинировать разные хеш-функции, надеясь, что результат будет более надежным.
Хотя на практике пользы от этого мало. Все, к чему эти действия приводят – это появление проблем совместимости, а иногда они могут сделать хеш-коды даже менее надежными. Никогда не пытайтесь изобрести свой собственный алгоритм шифрования, всегда используйте стандарт, который был разработан экспертами.
Некоторые могут поспорить, что использование нескольких хеш-функций делает процесс вычисления хеш-кодов более медленным, поэтому дешифрование становится медленнее, однако, как мы увидим позже, существует более разумный способ сделать процесс взлома более медленным.
Ниже приведены некоторые примеры чокнутых хеш-функций, которые я когда-либо встречал на форумах в Интернете.
Радужные таблицы и таблицы поиска работают только потому, что каждый пароль хешируется совершенно одинаковым способом. Если два пользователя имеют один и тот же пароль, у них будет совпадать и хеш-код пароля.
Мы можем предотвратить эти атаки, внеся случайную составляющую в каждый хеш-код; таким образом, когда одинаковый пароль хешируется дважды, хеш-коды получаются разные.
Мы можем внести случайную составляющую в хеш-коды, добавив в конец или в начало пароля случайную строку, называемую « соль », перед операцией хеширования. При этом, как показано в примере выше, всякий раз получаются совершенно разные строки из одного и того же хеш-кода пароля.
Чтобы проверить, корректен ли пароль, нам нужна соль, поэтому обычно ее сохраняют в базе данных пользовательских аккаунтов вместе с хеш-кодом, или как часть самой строки хеш-кода.
Соль не обязательно держать в секрете. Просто при использовании случайной величины для построения хеш-кода таблицы поиска, обратные таблицы поиска и радужные таблицы становятся неэффективными. Злоумышленник не узнает заранее, какая будет соль, поэтому он не может предварительно вычислить таблицу поиска или радужную таблицу.
Если пароль каждого пользователя хешируется с помощью разной соли, атака с использованием обратной таблицы поиска также не будет работать.
В следующей секции мы рассмотрим распространенные ошибки при реализации соли.
НЕВЕРНЫЙ способ : короткая соль и повторное использование соли
Эта секция охватывает другое распространенное заблуждение насчет хеширования паролей: дурацкие комбинации хеш-алгоритмов. Очень легко увлечься и попытаться комбинировать разные хеш-функции, надеясь, что результат будет более надежным.
Хотя на практике пользы от этого мало. Все, к чему эти действия приводят – это появление проблем совместимости, а иногда они могут сделать хеш-коды даже менее надежными. Никогда не пытайтесь изобрести свой собственный алгоритм шифрования, всегда используйте стандарт, который был разработан экспертами.
Некоторые могут поспорить, что использование нескольких хеш-функций делает процесс вычисления хеш-кодов более медленным, поэтому дешифрование становится медленнее, однако, как мы увидим позже, существует более разумный способ сделать процесс взлома более медленным.
Ниже приведены некоторые примеры чокнутых хеш-функций, которые я когда-либо встречал на форумах в Интернете:
Примечание : этот раздел оказался противоречивым. На мою электронную почту пришло много писем, в которых утверждалось, что замудренные хеш-функции – это хорошая вещь, потому что лучше, если злоумышленник не знает, какая хеш-функция используется.
Тогда менее вероятно наличие у злоумышленника предварительно вычисленных радужных таблиц для мудреной хеш-функции, и вычисление хеш-функции занимает больше времени.
Злоумышленник не может атаковать хеш-код, когда он не знает алгоритм, но учитывая принцип Керкгоффса, взломщик обычно обладает доступом к исходному коду (особенно если это приложение бесплатное или с открытым исходным кодом), и ему известны несколько пар пароль/хеш-код из целевой системы, поэтому не составляет никакого труда выполнить реверсивное программирование алгоритма.
Вычисление мудреных хеш-функций действительно занимает больше времени, но только с небольшим константным коэффициентом. Лучше использовать итеративный алгоритм, спроектированный так, чтобы его было очень сложно распараллелить (такие алгоритмы обсуждаются ниже). А, добавление соли в хеш-код, выполненное должным образом, решает проблем радужных таблиц.
Если вы действительно хотите использовать стандартизованную « чокнутую » хеш-функцию, например, HMAC, тогда нет проблем. Но если причина для этого – сделать вычисление хеш-кода медленнее, сначала прочитайте секцию ниже о растяжении ключа.
Сравните эти незначительные преимущества с риском случайного внедрения совершенно ненадежной хеш-функции и проблемами несовместимости, создаваемые мудреными хеш-функциями. Без сомнения, лучше всего использовать стандартные и хорошо протестированные алгоритмы.
Коллизии хеш-функций
Так как хеш-функции отображают произвольное количество данных в строке фиксированной длины, должны существовать такие входные данные, хеш-коды которых совпадают. Криптографические хеш-функции разработаны так, что такие коллизии встретить невероятно трудно. Время от времени криптографы находят « атаки » на хеш-функции, которые облегчают нахождение коллизий.
Недавний пример – это хеш-функция алгоритма MD5, для которой действительно были найдены коллизии.
Атаки коллизии – это признак того, что существует вероятность наличия для строки, отличной от пароля пользователя, точно такого же хеш-кода. Однако нахождение коллизий даже в такой слабой хеш-функции как MD5 требует большой вычислительной мощности, поэтому маловероятно, что такие коллизии « нечаянно » произойдут на практике.
ВЕРНЫЙ способ : как производить хеширование правильно
Эта секция описывает, как именно должны быть зашифрованы пароли. Первый подраздел охватывает основы – все, что жизненно необходимо. Следующие подразделы объясняют, как основы могут быть расширены, чтобы сделать хеш-коды еще более устойчивыми к взломам.
Основы : Хеширование с солью
Мы увидели, как злобные хакеры могут взломать простые хеш-коды очень быстро, используя таблицы поиска и радужные таблицы. Мы узнали, что внесение случайной составляющей в хеширование при помощи соли является решением для этой проблемы. Но как генерировать соль, и как применить ее к паролю?
Как следует из названия, криптографически стойкие генераторы предназначены быть криптографически надежными, в том смысле, что они обеспечивают высокий уровень случайности и совершенно непредсказуемы.
Мы не хотим, чтобы наша соль была предсказуема, поэтому мы и должны использовать криптографически стойкий генератор.
В таблице, приведенной ниже, перечислены некоторые такие генераторы, существующие для распространенных платформ программирования:
Соль должна быть своя для каждого пользователя и пароля. Каждый раз, когда пользователь создает учетную запись или изменяет свой пароль, пароль должен быть захеширован с помощью новой случайной соли. Никогда не используйте соль повторно.
Также соль должна быть длинной, поэтому существует очень много возможных вариантов. Опираясь на жизненный опыт, следует использовать соль, по меньшей мере, той же длины, что и выход хеш-функции. Соль должна быть сохранена в таблице учетных записей пользователей вместе с хеш-кодом.
Внизу этой страницы представлены реализации « соленого » хеширования паролей на PHP, C#, Java и Ruby.
В веб-приложениях всегда вычисляйте хеш-код на сервере
Если вы пишите веб-приложение, вам, возможно, интересно, где же производить операцию вычисления хеш-кодов. Должен ли пароль быть захеширован в браузере пользователя с помощью JavaScript, или он должен быть отправлен на сервер «открытым текстом» и захеширован там?
Даже если вы вычисляете хеш-код пользовательского пароля, используя JavaScript, вы все равно должны произвести хеширование хеш-кодов на сервере.
Предположим, что веб-сайт производит вычисление хеш-кода паролей в браузерах пользователей без хеширования хеш-кодов на сервере. Для аутентификации пользователя этот веб-сайт будет принимать хеш-код от браузера и проверять, совпадает ли этот хеш-код с тем, что хранится в базе данных. Кажется, что это более безопасно, чем просто хеширование на сервере, так как пароли пользователей никогда не отправляются на сервер, но это не так.
Проблема в том, что хеш-код на стороне клиента по логике становится пользовательским паролем. Все, что пользователю нужно сделать для аутентификации, это указать серверу хеш-код своего пароля. Если бы злоумышленник получил хеш-код пользователя, он мог бы использовать его для аутентификации на сервере, не зная пользовательского пароля!
Таким образом, если злоумышленник каким-то образом украдет базу данных хеш-кодов с этого гипотетического веб-сайта, он получит непосредственный доступ к учетной записи каждого пользователя без необходимости угадывать какой-либо пароль.
Это не означает, что вам не следует вычислять хеш-код в браузере, но если вы делаете это, вы обязаны производить хеширование и на сервере тоже.
Хеширование в браузере – это, определенно, хорошая идея, но учитывайте следующие моменты в ваших проектах: Хеширование пароля на стороне клиента не замещает HTTPS (SSL/TLS).
Если соединение между браузером и сервером ненадежно, третья сторона может изменить код JavaScript во время загрузки, чтобы удалить функцию хеширования и получить пароль пользователя:
Усложняем взлом пароля: медленные хеш-функции
Соль гарантирует, что злоумышленники не смогут использовать специализированные атаки, такие как таблицы поиска и радужные таблицы, чтобы быстро взламывать большое количество хеш-кодов, но это не мешает им запустить атаку по словарю или атаку полным перебором индивидуально для каждого хеш-кода.
Высококачественные видеокарты и правильно подобранное железо могут вычислять миллиарды хеш-кодов в секунду, поэтому эти атаки до сих пор очень эффективны. Чтобы сделать их менее эффективными, мы можем использовать технологию под названием растяжение ключа.
Главная идея – сделать хеш-функцию очень медленной, чтобы даже с помощью быстрой видеокарты и специального оборудования, атаки по словарю и полным перебором были слишком медленными, чтобы оправдывать себя. Цель – сделать хеш-функцию достаточно медленной, чтобы помешать атакам, но при этом довольно быстрой, чтобы не создавать видимой задержки для пользователя.
Растяжение ключа реализуется при помощи специального типа хеш-функции, нагружающей ЦПУ. Не пытайтесь изобрести свою собственную – простое итеративное хеширование хеш-кода пароля не достаточно, так как оно может быть распараллелено на аппаратным уровне и выполнено так же быстро, как и обычный хеш-код.
Эти алгоритмы принимают в качестве аргумента коэффициент надежности или счетчик итераций. Эта величина определяет, насколько медленной будет хеш-функция.
Для настольного программного обеспечения или приложений для смартфонов самый лучший способ выбрать этот параметр – это запустить короткий тест на устройстве, чтобы найти величину, при которой хеш-код вычисляется примерно полсекунды. Таким образом, ваша программа может быть максимально надежной, не влияя на работу пользователя.
Если вы применяете хеширование растяжения ключа в веб-приложении, вы должны знать, что вам потребуются дополнительные вычислительные ресурсы, чтобы обрабатывать огромный объем запросов аутентификации, и что растяжение ключа облегчает выполнение атак типа « отказ в обслуживании » (DoS) на ваш сайт.
Я все же рекомендую использование растяжение ключа, но с небольшим значением счетчика итераций. Вам нужно вычислить счетчик итераций, основываясь на ваших вычислительных ресурсах и ожидаемой максимальной скорости запросов на проверку подлинности.
Угроза отказа в обслуживании может быть устранена, если заставить пользователей вводить капчу каждый раз, когда они входят в учетную запись. Всегда проектируйте вашу систему так, чтобы счетчик итераций мог быть увеличен или уменьшен в будущем.
Счетчик итераций должен быть установлен достаточно небольшим, чтобы система могла использоваться с более медленными клиентами, такими как мобильные устройства. Также система должна передавать вычисления серверу, если пользовательский браузер не поддерживает JavaScript.
Растяжение ключа на стороне клиента не отменяет необходимость хеширования на сервере. Вы должны хешировать хеш-код, сгенерированный клиентом так же, как если бы хешировали обычный пароль.
Хеш-коды, которые невозможно взломать: имитовставка и аппаратное хеширование паролей
Пока злоумышленник может использовать хеш-код для проверки, верен ли предполагаемый пароль или нет, он может применить к хеш-коду атаку по словарю или атаку полным перебором. Следующим шагом является добавление секретного ключа к хеш-коду.
Это не так легко, как кажется. Ключ нужно держать в секрете от злоумышленников, даже в случае взлома. Если злоумышленник получает полный доступ к системе, он будет способен украсть ключ вне зависимости от того, где он сохранен.
Я настоятельно рекомендую этот подход для любого крупномасштабного (более 100 000 пользователей) сервиса. А для любого сервиса, содержащего более чем 1 000 000 пользовательских аккаунтов, я считаю, что это просто обязательно.
Если вы не можете позволить себе несколько выделенных серверов или специальные аппаратные устройства, вы все равно можете получить некоторую пользу от имитовставки на стандартном веб-сервере.
Большинство баз данных взламываются с помощью атак SQL-инъекциями, которые, в большинстве случаев, не дают злоумышленникам доступ к локальной файловой системе (отключите доступ на вашем SQL сервере к локальной файловой системе, если он поддерживает такую функцию).
Не прописывайте ключ в исходном коде, генерируйте его случайным образом, когда приложение установлено. Это не так надежно, как использование отдельной системы для вычисления хеш-кода паролей, потому что, если в веб-приложении есть уязвимости к SQL-инъекциям, вероятно, существуют и другие виды уязвимостей, такие как подключение к локальному файлу, которые злоумышленник мог бы использовать для чтения файла с секретным ключом. Но лучше это, чем ничего.
Пожалуйста, обратите внимание, что имитовставка не избавляет от необходимости использования соли. Умные злоумышленники в конечном итоге найдут способы скомпрометировать ключи, поэтому важно, чтобы хеш-коды были дополнительно защищены солью и растяжением ключа.
5. Другие методы защиты
Хеширование защищает пароли в случае нарушения безопасности. Это не делает приложение в целом более безопасным. Многое еще нужно сделать, чтобы предотвратить в первую очередь кражу хеш-кодов (и других пользовательских данных).
Даже опытные разработчики должны быть образованы в сфере безопасности для того, чтобы писать безопасные приложения. Отличным источником для изучения уязвимостей веб-приложений является открытый проект обеспечения безопасности веб-приложений (англ. The Open Web Application Security Project – OWASP ). Хорошим введением служит OWASP Top Ten Vulnerability List (список топ-10 уязвимостей от OWASP).
Если вы не разобрались со всеми уязвимостями в списке, не пытайтесь написать веб-приложение, имеющее дело с конфиденциальными данными. Работодатель ответственен за обеспечение всех разработчиков надлежащей подготовкой в сфере разработки безопасных приложений.
Хорошей идеей является наличие « теста на проникновение » третьей стороны для вашего приложения. Даже самые лучшие программисты допускают ошибки, поэтому хорошо бы иметь эксперта по безопасности, проверяющего код на потенциальные уязвимости.
Найдите надежную организацию (или наймите сотрудников) для проверки вашего кода на постоянной основе. Процесс проверки безопасности нужно начинать на ранней стадии проекта и продолжать на протяжении всей разработки.
Также важно проводить мониторинг вашего сайта, чтобы обнаружить нарушение безопасности, если это произошло. Я рекомендую нанять по крайне мере одного человека, единственной работой которого будет обнаружение и реагирование на бреши в безопасности.
Если нарушение не было обнаружено, злоумышленник может через ваш сайт заражать компьютеры посетителей вредоносными программами, поэтому чрезвычайно важно, чтобы бреши в безопасности были обнаружены и устранены максимально быстро.
6. Часто задаваемые вопросы
Поэтому я не рекомендую применять их. Исключением из этого правила служит PBKDF2, который реализован с использованием алгоритма SHA1 в качестве основной хеш-функции.
Каким образом следует разрешать пользователям сбрасывать их пароль, если они забыли его?
По моему личному мнению, все механизмы сброса паролей, широко используемые сегодня, ненадежны. Если у вас есть высокие требования к безопасности, как например, для сервиса шифрования, не позволяйте пользователям сбрасывать свои пароли.
Большинство веб-сайтов используют так называемое зацикливание почты (англ. email loop ) для аутентификации пользователей, которые забыли пароль. Для этого сгенерируйте случайный одноразовый маркер, тесно связанный с учетной записью. Включите его в ссылку для сброса пароля, отправляемую на адрес электронной почты пользователя.
Когда пользователь нажмет на ссылку сброса пароля, содержащую допустимый маркер, выдайте ему новый пароль. Убедитесь, что маркер тесно связан с пользовательским аккаунтом, и злоумышленник не сможет использовать маркер, отосланный на его адрес электронной почты, для сброса пароля другого пользователя.
Действие маркера должно истекать через 15 минут или после использования, в зависимости от того, что наступит раньше.
Также неплохо, аннулировать любой существующий маркер, когда пользователь входит в учетную запись (значит, он помнит пароль) или запрашивать другой маркер сброса. Если маркер не имеет срока действия, его можно сколько угодно использовать для взлома пользовательского аккаунта.
Почта ( SMTP ) – это простой протокол, и в Интернете могут существовать вредоносные маршрутизаторы, регистрирующие почтовый траффик. И почтовый аккаунт пользователя (включая ссылку сброса) может подвергаться риску еще долгое время после того, как пароль был изменен.
Устанавливая срок действия маркера настолько малым, насколько возможно, вы снижаете подверженность пользователей к атакам подобного рода.
Злоумышленники будут способны изменять маркеры, поэтому не храните в них информацию о пользовательской учетной записи или о времени истечении срока действия маркера. Они должны быть непредсказуемым случайным массивом двоичных данных, используемым только для идентификации записи в таблице базы данных.
Никогда не посылайте пользователю новый пароль по электронной почте. Не забывайте применять новую случайную соль, когда пользователи сбрасывают свои пароли. Не используйте повторно ту соль, которая была задействована для хеширования старого пароля.
Что делать если моя база данных пользовательских аккаунтов имеет утечку/взломана?
Ваша первоочередная задача – определить, каким образом система была нарушена и устранить уязвимость, используемую злоумышленником для взлома. Если у вас нет опыта реагирования на нарушения в защите, я настоятельно рекомендую нанять стороннюю фирму по информационной безопасности.
Прикрыть брешь в защите и надеяться, что никто ничего не заметил – может это и звучит заманчиво. Однако попытка скрыть нарушение только навредит вашей репутации, потому что вы подвергаете ваших пользователей дальнейшему риску, не сообщая им, что их пароли и другая личная информация могут быть скомпрометированы.
Вы должны информировать ваших пользователей как можно раньше – даже если вы еще не полностью поняли, что произошло. Разместите на главной странице вашего веб-сайта сообщение, содержащее ссылку на страницу с более подробной информацией, и разошлите уведомление каждому пользователю на электронную почту, если это возможно.
Объясните вашим пользователям, как именно защищены их пароли (надеюсь, захешированы с солью) и что, несмотря на то, что они защищены соленым хеш-кодом, злоумышленник все равно может применить к хеш-кодам атаку по словарю или полным перебором.
Злоумышленники воспользуются любым найденным паролем, чтобы попытаться войти в аккаунт пользователя на другом веб-сайте, рассчитывая, что пользователь использует один и тот же пароль на обоих сайтах. Сообщите вашим пользователям об этом риске и порекомендуйте, чтобы они изменили свои пароли на всех веб-сайтах или сервисах, где использовали тот же пароль.
Заставьте их изменить свои пароли для вашего сервиса в следующий раз, когда они войдут в систему. Большинство пользователей попытается « поменять » пароль на первоначальный, чтобы быстро обойти вынужденное изменение. Используйте хеш-код текущего пароля, чтобы гарантировать, что они не смогут сделать этого.
Вероятно, даже с соленым медленным хешированием, злоумышленник будет в состоянии взломать несколько слабых паролей очень быстро. Чтобы уменьшить возможности злоумышленника использовать эти пароли, нужно, в дополнении к текущему паролю, применить зацикливание электронной почты для аутентификации, пока пользователь не изменит свой пароль.
Смотрите ответ на предыдущий вопрос « Каким образом следует разрешать пользователям сбрасывать их пароль, если они забыли его », чтобы получить подсказки по реализации аутентификации с помощью зацикливания электронной почты.
Также сообщите своим пользователям, какая личная информация была сохранена на веб-сайте. Если ваша база данных содержит номера кредитных карт, вам нужно проинструктировать ваших пользователей, чтобы они внимательно следили за своими недавними и будущими операциями и аннулировали кредитную карту.
Какой должна быть моя политика паролей? Нужно ли настаивать на сложных паролях?
Если у вашего сервиса нет строгих требований к безопасности, тогда не ограничивайте своих пользователей. Я рекомендую показывать пользователям информацию о надежности их пароля, пока они вводят его, позволив им самим решать, насколько надежным должен быть их пароль.
Если же у вас есть особые требования к безопасности, установите минимальную длину пароля в 12 символов и обязательное наличие по крайней мере двух букв, двух цифр и двух символов.
Не принуждайте пользователей изменять свой пароль чаще чем раз в полгода, так как это может привести к «усталости» пользователя, и он, с меньшей вероятностью, выберет хороший пароль.
Вместо этого научите пользователей никогда никому не рассказывать свой пароль и менять свой пароль всякий раз, когда они чувствуют, что он был подвергнут риску.. В контексте бизнес-решений, следует поощрять сотрудников использовать рабочее время для запоминания и практики их паролей.
Если у злоумышленников есть доступ к моей базе данных, могут ли они просто заменить хеш-код моего пароля на свой собственный хеш-код и войти в аккаунт?
Да, но если у кого-то есть доступ к вашей базе данных, у них, вероятно, уже есть доступ ко всему на вашем сервере, поэтому им не нужно будет входить в ваш аккаунт, чтобы получить, что они хотят. Целью хеширования паролей (говоря о веб-сайте) является не защита веб-сайта от взлома, а защита паролей, если взлом произошел.
Вы можете защитить хеш-коды от замены во время атаки SQL-инъекцией, подключаясь к базе данных с помощью двух пользователей с разными правами доступа. Один – для кода « создать аккаунт », а другой – для кода « вход в систему ». Код « создать аккаунт » должен иметь возможность читать и писать в таблицу пользователей, а код « вход в систему » должен только читать.
Почему я должен использовать специальный алгоритм, например, HMAC? Почему я не могу просто добавить пароль к секретному ключу?
Это значит, что имея хеш-код H(ключ + сообщение), злоумышленник может вычислить H(pad(ключ + сообщение) + добавление) при неизвестном значении ключа.
Если хеш-код использовался в качестве кода аутентификации сообщения, а ключ был задействован для того, чтобы не позволить злоумышленнику изменить сообщение и подменить его другим действительным хеш-кодом, то эта система дала сбой, так как у злоумышленника теперь есть корректный хеш-код от комбинации (сообщение + добавление).
Пока не ясно, как злоумышленники могли бы использовать такую атаку для более быстрого взлома хеш-кодов паролей. Однако, из-за существования этой атаки, использование простых хеш-функций для имитовставки считается плохой практикой.
В один прекрасный день какой-нибудь умный криптограф может придумать хитрый способ, как использовать эти атаки для более быстрого взлома, поэтому используйте HMAC.
Соль должна идти до или после пароля?
Не имеет значения, но выберете что-то одно и придерживайтесь этого варианта для обеспечения совместимости. В большинстве случаев принято располагать соль перед паролем.
Почему код для хеширования, приведенный в этой статье, сравнивает хеш-коды за время « неизменной длины » («l ength-constant » time)?
Сравнение хеш-кодов за время « неизменной длины » гарантирует, что злоумышленник не сможет извлечь хеш-код пароля из системы в режиме онлайн, используя атаку по времени, а затем взломать в автономном режиме.
Стандартным способом проверки, одинаковы ли две последовательности битов (т.е. две строки), является сравнение первого бита, затем второго, третьего и т.д. Как только вы найдете несовпадающий бит, становится понятно, что строки разные, и можно сразу же вернуть отрицательный результат.
Если сравнение прошло через обе строки, и не было найдено несовпадающих битов, значит строки одинаковые и можно вернуть положительный результат. Таким образом, сравнение двух строк может занимать разное количество времени, в зависимости от того, насколько эти строки совпадают.
Например, стандартный алгоритм сравнения строк « xyzabc » и « abcxyz » немедленно обнаружит, что первые символы отличаются, и не потрудится проверить оставшуюся часть строки. С другой стороны, при сравнении строк « aaaaaaaaaaB » и « aaaaaaaaaaZ «, алгоритм сравнения просматривает последовательность символов «a» прежде, чем определит, что строки неодинаковы.
Предположим, что злоумышленник хочет взломать онлайн систему, ограничивающую число попыток аутентификации до одной в секунду. Также допустим, что злоумышленник знает все параметры хеш-кода пароля (соль, тип хеш-функции и т.п.) кроме самого хеш-кода и (очевидно) пароля.
Если злоумышленник сможет точно измерить, сколько времени занимает у онлайн системы сравнение хеш-кода реального пароля с хеш-кодом пароля, который предоставляет злоумышленник, он может использовать атаку по времени для извлечения части хеш-кода и взломать его затем в автономном режиме, минуя тем самым ограничения системы.
Сначала злоумышленник находит 256 строк, чьи хеш-коды начинаются со всех возможных битов. Он отправляет каждую строку в онлайн систему, фиксируя время, которое требуется системе, чтобы отреагировать.
Строка, обработка которой занимает наибольшее время, является той, чей первый бит хеш-кода совпадает с первым битом настоящего хеш-кода. Теперь злоумышленник знает первый бит, и может продолжить атаку аналогичным образом для второго бита, затем третьего и т.д.
После того, как злоумышленник узнает хеш-код, он может использовать свои собственные аппаратные средства, чтобы взломать его, не будучи ограниченным скоростью системы.
Как работает код SlowEquals?
Ответ на предыдущий вопрос объясняет, зачем нужна функция SlowEquals, здесь же поясняется, как на самом деле работает код:
Для проверки целых чисел на равенство в коде используется оператор исключающее « ИЛИ » – « ^ » вместо оператора « == «. Почему объясняется ниже.
Причина, по которой нам нужно использовать исключающее « ИЛИ » вместо оператора « == » для сравнения целых чисел, заключается в том, что обычно « == » переводится/компилируется/интерпретируется как ветвление.
Например, на C код « diff &= a == b » может скомпилироваться в следующие ассемблерные инструкции x86:
Из-за ветвления, код выполняется за разное количество времени, в зависимости от равенства чисел и внутреннего состояния предсказателя ветвлений в ЦПУ.
Код C « diff |= a ^ b » будет скомпилирован примерно в следующий ассемблерный код, время выполнения которого не зависит от равенства чисел:
Зачем беспокоиться о хешировании?
Ваши пользователи вводят свои пароли на вашем веб-сайте. Они доверяют вам свою безопасность. Если ваша база данных будет взломана, а пароли пользователей незащищены, то злоумышленники смогут использовать эти пароли для компрометации аккаунтов ваших пользователей на других веб-сайтах и серверах (большинство людей везде используют один и тот же пароль).
Не только ваша безопасность под угрозой, но и безопасность ваших пользователей. И именно вы ответственны за их безопасность.