Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codedokode/9576319 to your computer and use it in GitHub Desktop.
Save codedokode/9576319 to your computer and use it in GitHub Desktop.
Соли @ хешируй

Этот урок переехал по адресу: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md

Здесь старая версия урока, которая больше не обновляется.


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

Соли @ хешируй

Для начала, никогда не храни открытые пароли. Храни соленые хеши от них. Хеш-функция, например md5, sha1 (про них написано в вики, почитай) — это практически необратимая функция. То есть получить хеш по паролю просто, а вот восстановить пароль, имея хеш практически невозможно — надо перебирать все возможные варианты паролей и сравнивать получившиеся хеши.

Почитать про md5: http://ru.wikipedia.org/wiki/Md5

Какой смысл в хэше, если md5 все равно можно расшифровать? Пусть даже перебором?

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

Ок, достаточно ли использовать хеширование и хранить только хеши?

Нет! Без так называемой «соли» многие пароли можно подобрать за секунду если там использовать просто md5(pass). Не веришь? Читай ниже.

Что такое соль? Что значит «соленый хеш»?

Соль — случайно сгенерированная последовательность символов, которая хранится рядом с хешем. Дан пароль $pass = "123456", мы генерируем случайную соль например $salt = 'A&%6t*(k:' и получаем хеш от «соль + пароль»: $hash = md5($salt . $pass). В базу сохраняется отдельно использованная соль (она для каждого пользователя своя), отдельно хеш.

Теперь попробуем применить математику и посчитать насколько надежны разные способы хеширования. Сейчас подбор пароля делается 2 способами:

Способ 1

Перебираем все возможные пароли, начиная например с 1111111 и заканчивая zzzzzzz и вычисляем от каждого md5-хеш. При этом число вариантов, которые надо подобрать, зависит от длины и набора символов (чем их больше тем больше перебирать). Скорость перебора md5 на топовых видеокартах составляет около 10 миллиардов в секунду ( http://www.opennet.ru/opennews/art.shtml?num=30201 и http://hashcat.net/oclhashcat/ ). А ведь можно взять не одну видеокарту, а много, если очень надо.

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

Считаем число вариантов.

36^6 — значит 36 в 6-й степени, то есть 36*36*36*36*36*36 если что.

  • Если в пароле 12 цифр 0-9: число комбинаций = 10^12 = 1000 миллиардов = 100 секунд перебора на 1 видеокарте (1 секунда на 100 карточках параллельно).
  • Если 6 букв a-z или цифр 0-9. Число вариантов = 36^6 (считаем гуглом) = 2 млрд. Хехе, меньше секунды.
  • Если 6 букв a-zA-Z (добавим маленькие и большие буквы) и 0-9. Комбинаций 62^6 = 56 млрд. 6 секунд перебора.
  • Если в пароле 8 букв a-zA-Z и цифр 0-9. Комбинаций уже 62^8 = 218 триллионов. Это 22000 секунд перебора (в часе 3600 секунд, так что выходит 6 часов) на 1 карточке или 220 секунд на 100 карточках. Ого, не очень-то надежно.
  • Если в пароле 10 символов a-zA-Z0-9 + 20 знаков вроде минус, плюс.. то выходит 82^10 комбинаций ~ 10^19 и перебирать их 10^9 секунд на одной карте (11500 дней) или 115 дней на сотне карточек.

Люди часто ставят паролем не бредовый набор букв, а слова или куски слов. Значит, какие-то символы рядом встречаются чаще, их можно перебирать в первую очередь тем самым сокращая число вариантов и ускоряя время нахождения.

В общем, видишь, без добавления соли пароли подберутся на раз. И не все же ставят 10-символьные пароли, у многих там просто слово или цифры.

Способ 2

Есть еще другой вариант — скачать огромные радужные таблицы (читай в вики про них) где хранятся уже рассчитанные цепочки хешей (для простых паролей). И конечно все хеши от обычных паролей длиной до 10 символов там уже есть (больше нету, так как они начинают занимать гигабайты. Но это вопрос времени, когда жесткие диски станут больше). Если ты хранишь в базе md5(pass) она вскроется мигом. Таблицы можно скачать тут: https://www.freerainbowtables.com/en/tables2/ (если не открывается, выбери английский язык и открой ссылку еще раз).

Вот пример такой таблицы: md5_loweralpha-numeric#1-10 588 GB - подбирает пароли без соли до 10 символов [a-z0-9].

Заметь что в будущем компьютеры будут мощнее, и значит подбираться пароли будут быстрее. Теперь подумаем как защититься и усложнить жизнь взломщикам:

  • разрешаем использовать больше видов символов в паролях
  • добавляем соль. С солью не получится параллельно подбирать все хеши так как у каждого юзера соль своя и каждый хеш надо перебирать отдельно, что сильно замедляет взлом. Также, при добавлении соли даже к простому паролю он по сути становится длинным и сложным и его не будет в радужных таблицах (123456 → Y^juYUHkd%$fdtd123456). Опять же, соль должна быть подлиннее и содержать спецсимволы чтобы было больше комбинаций для перебора. Ну конечно, простые пароли типа 123456 все равно вскроют, так как их при переборе проверяют в первую очередь. А вот сложные придется подбирать долго.
  • используем вместо md5 более тяжелые для вычисления алгоритмы вроде bcrypt, который сделан так, что его нельзя перебрать быстрее чем за опредеенное время (и ты можешь указать требемый уровень сложности).

С правильным подходом даже простой md5 замучаешься расшифровывать.

Еще

Вычисление хеша md5 очень быстро делается на современном железе. Чтобы усложнить перебор, можно использовать более тяжелые для вычисления хеши, например http://ru.wikipedia.org/wiki/Bcrypt и http://ru.wikipedia.org/wiki/Scrypt где можно задавать сложность вычисления хеша (а в scrypt — еще и необходимый объем памяти).

В php 5.5 сделали стандартные функции хеширования паролей password_*: http://habrahabr.ru/post/194972/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment