Правильно храним пароли в БД

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

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

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

Минус тут единственный – при запросе восстановления пароля пользователем мы не сможем дать ему этот пароль, т.к. не знаем его, но можем сгенерировать новый и отправить ему по почте (или на ушко шепнуть, если он рядом icon smile Правильно храним пароли в БД ).

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

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

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

Соль – это некоторая последовательность байт, которая прибавляется каким-то образом к паролю (в нашем случае – к его хэшу). Подробнее про соль в криптографии можно прочитать в википедии: [ссылка]

Сейчас некоторые из тех, кто читают эту статью, наверняка начали критиковать меня. Из-за чего? Потому что храним хэш и соль в одном месте – в базе. Т.е. если злоумышленник знает алгоритм формирования пароля и достанет хэш (хотел написать хлеб icon smile Правильно храним пароли в БД ) с солью, то он без труда сможет организовать атаку по словарю или брутфорс. Да, тут сложно не согласиться, но согласитесь и Вы со мной – сложность перебора в нашем случае увеличивается и такая брутфорс атака будет производиться медленнее, чем если бы это был просто поиск совпадений хэш-значений (с хеш-значением пароля), полученных в результате перебора паролей. Но зачастую код, отвечающий за формирование пароля, скрыт от злоумышленника. Потом, если пользователя заставлять запоминать соль вместе с паролем – ему будет сложнее. Лично я не видел еще сайтов, которые спрашивают у тебя не только пароль, но еще и соль (куда ее ему дать? На монитор насыпать может? icon smile Правильно храним пароли в БД . Ааа, ну да. В textbox ввести в дополнительный icon smile Правильно храним пароли в БД ).

Да и пароли нужно выбирать посложнее.

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

	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-хэш, можно посмотреть, какие пароли по нему могут быть получены. Адрес этого сервиса – http://gdataonline.com/. Может быть есть еще какие-нибудь подобные сайты, но я не искал.

На сегодня все.
Всего доброго! icon smile Правильно храним пароли в БД





Читайте также:



14 Ответов на “Правильно храним пароли в БД”

  1. Глеб Белогорцев
    Февраль 13th, 2009

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

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

    Кстати, насколько я знаю, Rainbow-таблицы (на которых основана работа того же GData) есть не только для md5, но и для sha1, так что он не намного безопаснее.

  2. miraz
    Февраль 13th, 2009

    Спасибо за столь подробную информацию, пароль это неотъемлемая часть…..и главное что он был надежным!!

  3. novice
    Февраль 13th, 2009

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

  4. Глеб Белогорцев
    Февраль 13th, 2009

    А почему потребуется больше времени?
    Допустим, злоумышленник знает, что
    $hash = md5($salt.$password);
    и вытащил из базы
    $hash = ’6547436690a26a399603a7096e876a2d’;
    $salt = ‘bbb’;
    Он будет перебирать варианты $password и смотреть, какой даст правильный хэш при таком алгоритме. В случае, если бы “соль” не использовалась, он перебирал бы такие же пароли и нашёл бы правильный за такое же число попыток. Или вы что-то другое имели в виду?

  5. novice
    Февраль 13th, 2009

    Я имел в виду, что sha1($salt.sha1($pwd).$salt) должно длиться дольше, чем просто sha1($salt.$pwd)

  6. Igor
    Февраль 13th, 2009

    Я обычно шифрую пароли сначала md5 потом sha1 + добавляю соль

  7. Артемий
    Февраль 25th, 2009

    Вообще говоря сложность алгоритмов шифрования данных во многом определяется задачей. Например если мне нужно хранить пароль от профиля на форуме зачем его “солить”. Хранить md5($pwd) да и хватит.

  8. Lander
    Март 2nd, 2009

    Написано всё верно. Не подкопаешься. :)
    Единственное что мне не понятно – это по поводу сервиса с md5 хешами паролей. Соль как раз и вводится, что бы подобные сервисы не работали. К тому же в базе порядка 1 млрд паролей что составляет лишь ничтожную долю всех возможных значений. Объём 2^128 значени хранить не способен никто. А вообще спасибо. Инетресно было почитать. :)

  9. novice
    Март 2nd, 2009

    Да, я как раз имел в виду то, что сервис по извлечению возможной комбинации не поможет, если применять соль. Все правильно :)

  10. Lander
    Март 2nd, 2009

    novice, сорри. Значит я не правильно понял. :) Я понял, что использование SHA обусловлено тем, что сервис по восстановлению md5 уже есть. :)

  11. Денис Каратаев
    Июнь 3rd, 2009

    День добрый.
    Позволю себе добавить, чем еще SHA-1 лучше чем MD5.

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

    Добавляю Вас в RSS. Будем дружить :)

  12. Lander
    Июнь 4th, 2009

    Денис Каратаев, коллизии возникают в любой хеш функции! :) И, кстати, коллизию вычислить не сложно, достаточно использовать парадокс дня рождения. Но к сожалению это всё слабо применимо к реверсированию хеш-функций!

  13. Алекс
    Июнь 5th, 2009

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

  14. Денис Каратаев
    Июнь 5th, 2009

    >К слову, md5 уже взломали (вбейте в гугле md5 collision)

    да, я это и имел ввиду :)

Оставить комментарий


© 2008 - 2012 i-novice.net | Все права защищены.