Правильно храним пароли в БД
Как известно, хранить пароль в открытом виде в базе данных или еще где-то совсем не безопасно. Нелепо также наивно полагать, что если к базе имею доступ только я, то никто не сможет проникнуть внутрь, кроме меня, потому что только я знаю пароль.
К сожалению, ошибки в скриптах и различные уязвимости иногда позволяют прочесть данные с помощью сформированных специальным образом SQL-запросов. Разрабатывая какой-то скрипт, а может быть и большой проект, нужно заранее полагать, что доступ к таблице, хранящей какие-то пароли, все равно может быть получен.
Поэтому, вывод напрашивается сам собой – нужно хранить не пароли в открытом виде, а их хэш-значения. Более того, нужно хранить не чистые хэш-значения, а как бы модифицированные
Минус тут единственный – при запросе восстановления пароля пользователем мы не сможем дать ему этот пароль, т.к. не знаем его, но можем сгенерировать новый и отправить ему по почте (или на ушко шепнуть, если он рядом :)).
Сегодня мы попробуем сотворить метод, который будет превращать наш пароль не просто в хэш, из которого итак сложно получить исходный пароль (это справедливо не всегда), а хэш, полученный из пароля и так называемой соли – добавке к паролю, которая затем хэшируется и получается результат в виде нового хэша.
Сначала о том, как мы можем получить пароль из хэша. Прямым преобразованием конечно никак, т.к. хэш – необратим. Мы можем воспользоваться например брутфорс-атакой (т.е. перебором всех возможных комбинаций), или атакой по словарю (а вдруг пользователь задал в качестве пароля несложную последовательность символов, например, какое-нибудь слово или сочетания цифр).
Я предлагаю пароль хэшировать алгоритмом SHA1, затем прибавлять к нему соль и еще раз хэшировать полученный результат. Затем все это (полученный хэш и соль) сохранять в базе данных.
Соль – это некоторая последовательность байт, которая прибавляется каким-то образом к паролю (в нашем случае – к его хэшу). Подробнее про соль в криптографии можно прочитать в википедии: [ссылка]
Сейчас некоторые из тех, кто читают эту статью, наверняка начали критиковать меня. Из-за чего? Потому что храним хэш и соль в одном месте – в базе. Т.е. если злоумышленник знает алгоритм формирования пароля и достанет хэш (хотел написать хлеб :)) с солью, то он без труда сможет организовать атаку по словарю или брутфорс. Да, тут сложно не согласиться, но согласитесь и Вы со мной – сложность перебора в нашем случае увеличивается и такая брутфорс атака будет производиться медленнее, чем если бы это был просто поиск совпадений хэш-значений (с хеш-значением пароля), полученных в результате перебора паролей. Но зачастую код, отвечающий за формирование пароля, скрыт от злоумышленника. Потом, если пользователя заставлять запоминать соль вместе с паролем – ему будет сложнее. Лично я не видел еще сайтов, которые спрашивают у тебя не только пароль, но еще и соль (куда ее ему дать? На монитор насыпать может? :). Ааа, ну да. В textbox ввести в дополнительный :)).
Да и пароли нужно выбирать посложнее.
Привожу пример функции, генерящей сложный пароль заданной длины (это учебный пример, можно конечно придумать что-то получше):
function createpwd($length) { $chars = Array( 'a','b','c','d','e','f', '(',')','[',']','!','?', 'g','h','i','j','k','l', '&','^','%','@','*','$', 'm','n','o','p','r','s', '<','>','/','|','+','-', 't','u','v','x','y','z', 'A','B','C','D','E','F', 'G','H','I','J','K','L', 'M','N','O','P','R','S', 'T','U','V','X','Y','Z', '1','2','3','4','5','6', '7','8','9','0','.',',', '{','}','`','~' ); $pwd = ''; $chars_count = count($chars); for ($i = 0; $i < $length; $i++) { $index = rand(0, $chars_count - 1); $pwd .= $chars[$index]; } return $pwd; }
Генерируем пароль:
$pwd = createpwd(10);
Теперь нам нужно сгенерировать соль. Не будем писать для этого свою функцию – воспользуемся уже представленной. Пусть соль будет длиной в 6 случайных символов:
$salt = createpwd(6);
Теперь создаем хэш-значение из пароля и соли:
$hash = sha1($salt.sha1($pwd).$salt);
После всего этого мы должны сохранить содержимое переменных $salt и $hash в базу (не буду объяснять, как - думаю, все знают), а содержимое переменной $pwd как-то показать пользователю (а можно и на ушко шепнуть, как я уже писал).
При авторизации пользователя спрашиваем у него пароль и сохраняем его в переменную $pwd, затем берем из базы $salt и $hash и проверяем, правильно ли ввел пароль пользователь:
if (sha1($salt.sha1($pwd).$salt) == $hash) { echo ‘можешь проходить’; } else { echo ‘попробуй еще раз, но не хулигань!’; }
При таком раскладе лично я думаю, что взломать пароль будет очень сложно, особенно если он состоит не только из букв и цифр, но еще и из различных символов.
А на последок небольшой сюрприз. Помните, несколькими строчками выше я писал, что использую sha1? А ведь можно было md5. Почему я не использовал md5: оказывается, в интернете есть такой сервис, который хранит в своей базе огромное количество вычисленных хэшей. Т.е. достав какой-то md5-хэш, можно посмотреть, какие пароли по нему могут быть получены. Адрес этого сервиса - https://gdataonline.com/. Может быть есть еще какие-нибудь подобные сайты, но я не искал.
На сегодня все.
Всего доброго!
Позволю себе добавить, что использование случайной соли хорошо ещё вот в каком плане: если злоумышленник зарегистрирует на сайте несколько аккаунтов с распространёнными паролями, а потом украдёт базу, он не сможет по совпадению хэшей найти логины пользователей с этими простыми паролями.
А почему вы считаете, что если злоумышленник знает алгоритм шифрования, соль и хэш, это усложнит брутфорс? Ведь он как перебирал только варианты пароля (в случае отсутствия соли), так и будет перебирать.
Кстати, насколько я знаю, Rainbow-таблицы (на которых основана работа того же GData) есть не только для md5, но и для sha1, так что он не намного безопаснее.
Спасибо за столь подробную информацию, пароль это неотъемлемая часть…..и главное что он был надежным!!
Процесс перебора должен усложниться в плане времени. Для перебора должно потребоваться больше времени, чем если бы это было хэширование без соли. Насчет Rainbow-таблиц я так и предполагал, что есть и для других алгоритмов. Так что тут надо скорее всего сочетать алгоритмы хэширования, чтобы нельзя было воспользоваться такими таблицами.
А почему потребуется больше времени?
Допустим, злоумышленник знает, что
$hash = md5($salt.$password);
и вытащил из базы
$hash = ‘6547436690a26a399603a7096e876a2d';
$salt = ‘bbb';
Он будет перебирать варианты $password и смотреть, какой даст правильный хэш при таком алгоритме. В случае, если бы “соль” не использовалась, он перебирал бы такие же пароли и нашёл бы правильный за такое же число попыток. Или вы что-то другое имели в виду?
Я имел в виду, что sha1($salt.sha1($pwd).$salt) должно длиться дольше, чем просто sha1($salt.$pwd)
Я обычно шифрую пароли сначала md5 потом sha1 + добавляю соль
Вообще говоря сложность алгоритмов шифрования данных во многом определяется задачей. Например если мне нужно хранить пароль от профиля на форуме зачем его “солить”. Хранить md5($pwd) да и хватит.
Написано всё верно. Не подкопаешься.
Единственное что мне не понятно - это по поводу сервиса с md5 хешами паролей. Соль как раз и вводится, что бы подобные сервисы не работали. К тому же в базе порядка 1 млрд паролей что составляет лишь ничтожную долю всех возможных значений. Объём 2^128 значени хранить не способен никто. А вообще спасибо. Инетресно было почитать.
Да, я как раз имел в виду то, что сервис по извлечению возможной комбинации не поможет, если применять соль. Все правильно
novice, сорри. Значит я не правильно понял. Я понял, что использование SHA обусловлено тем, что сервис по восстановлению md5 уже есть.
День добрый.
Позволю себе добавить, чем еще SHA-1 лучше чем MD5.
Не так давно было обнаружено, что в алгоритме MD5 могут возникать коллизии (это когда один и тот же хэш может быть получен из разных строк), что небезопасно. Существуют группы хакеров, вычисляющих коллизии.
Добавляю Вас в RSS. Будем дружить
Денис Каратаев, коллизии возникают в любой хеш функции! И, кстати, коллизию вычислить не сложно, достаточно использовать парадокс дня рождения. Но к сожалению это всё слабо применимо к реверсированию хеш-функций!
Польза sha1 и соли заключается и в том, что, если взломщик сумел подобрать коллизию, войти на сайт с другим паролем будет уже невозможно.
К слову, md5 уже взломали (вбейте в гугле md5 collision)
>К слову, md5 уже взломали (вбейте в гугле md5 collision)
да, я это и имел ввиду