Комментарии 42
Спасибо за статью! Поясните, пожалуйста, один момент касательно функции password_hash().
Обратите внимание, что вам не нужно задавать значение соли или стоимостного параметра. Новый API всё сделает за вас.
А откуда password_hash() возьмет соль и где будет ее хранить?
А откуда password_hash() возьмет соль

Он ее сгенерирует
и где будет ее хранить?
Поскольку соль является частью хэша, то вам не придётся хранить её отдельно
Уже не первый раз читаю о том, что нельзя хранить просто хэши от пароля, чтобы они не были одинаковыми, что надо добавлять разную соль, да еще и хранить её рядом в базе. Это всё понятно, но почему нельзя к хэшированию добавить логин юзера, который обычно никогда не меняется, и какую-то общую соль? Её вообще можно хранить где-то отдельно. Пожалуйста, только не в карму!
а зачем? а менять логины нельзя? есть ведь blowfish, зачем все эти велосипеды?
Я же написал "который обычно никогда не меняется". А вы когда последний раз видели, чтобы логин у пользователя менялся? А если учесть, что логином обычно выступает почтовый адрес, то почти никогда. А если и давать юзеру менять почту-логин, то одновременно можно спросить для подтверждения текущий пароль — а с ним и перехэшировать и сохранить новый хэш.
Ну так проще вообще User ID использовать, он не меняется вовсе. Никто ж не запрещает. Тот же linkedin хранил пароли вообще черт-те как, до слива. Так что вряд ли вас упрекнут.
Но в то же время проще/надежнее прислушиваться к советам и мнениям специалистов в той или иной области, ибо:
Для затруднения брутфорс-атаки соль должна быть длиной не менее 64 символов.
и еще куча различных нюансов, о которых можно знать только если серьезно погружен в данную область
Вы невнимательны. Я предлагал одну большую общую соль, плюс логин (для разных результирующих хэшей), и плюс уже сам пароль. Тогда на глаз найти одинаковые пароли нельзя. А если соль не хранится там же в базе, а утекла только база, вы фиг разгадаете пароли.
В качестве соли можете использовать все что вам нравится. Хотите логин хэшируйте и используйте результат в качестве соли, хотите логин + общую соль. Если вас смущает хранение соли в базе, храните соль в файлах, NoSQL базе или в облаке, тоже вариантов куча.
Это я плохо написал, или вы все невнимательны?
Я предлагал хэшировать одну общую соль, плюс разные логины, плюс пароль. (hash($pass. $login. $mega_salt))
Общая соль достаточно большая, хранящаяся не в базе. Сервер, естественно, защищен.
Получается, что если утечёт база, как обычно и бывает (в новостях), то хакеры не смогут разгадать пароли или найти одинаковые.
Я вас прекрасно понял. Повторю еще раз: вы можете использовать в качестве соли все что угодно, логин, логин + соль, логин + соль + мега-соль и т.д. Хранить соль вы так же можете где угодно. Все это лишь частные случае одного решения: hash(пароль + соль).
Ваши разные соли будут очень похожи, что при взломе позволит сильно оптимизировать вычисления.
Не изобретайте велосипеды в криптографии, очень не рекомендую.
Подождите, при добавлении хотя бы одного нового символа хэш меняется весь. А соль применяется для того, чтобы сделать все хэши разными. Эта задача идеально решается с помощью подмешивания туда логина.
Ну не совсем идеально. Обычно соль это закрытые данные, некий случайный набор символов, а логин открыт. Теоретически можно даже догадаться, что в качестве соли используется логин (если логин не «вмешивается» каким то причудливым образом).
Ну почитайте другие мои комменты. При подмешивании логина соль может быть одинаковой, довольно большой. И как раз, храниться не в базе, а в другом месте. Если вдруг через инъекцию спалят всю базу, соль не утечёт.
Да я читал эти ваши комментарии. Можно вовсе не использовать общую соль, заменив ее на какие то операции над логином, делающие его более случайным.
Я не специалист, но попробую высказать свои мысли.)
добавить логин юзера
Логины обычно довольно простые и часто повторяются (в смысле на разных сайтах люди используют один логин). Поэтому использовать логин в качестве соли вряд ли целесообразно — ее легко узнать, легко подобрать.
С другой стороны, использовать логин вместе с солью, по большому счету, бессмысленно (если соль хороша, то прибавление к ней логина мало что изменит)
хранить соль где-то отдельно
Это, ИМХО, нереализуемо в принципе: чтобы иметь возможность аутентифицировать пользователя, веб-приложение должно иметь возможность эту соль считать. При этом неважно, где она будет храниться: в БД, в файле на диске, на внешнем FTP-сервере — в любом случае при компрометации web-сервера злоумышленник получит доступ к этой соли.
Единственный повод хранить соль не в БД, а где-то еще — это некоторое снижение рисков утечки паролей в том случае, если злоумышленник получит только доступ к БД (например, через SQL-инъекцию), но не сможет получить доступ к файлам и шеллу. Но стоит ли игра свеч — сказать сложно.
прибавление к ней логина мало что изменит
Тут вы неправы — весь хэш станет совершенно другим.
веб-приложение должно иметь возможность эту соль считать
Делаем отдельный сервер, который содержит соль и отдает только серверу с веб-приложением (по IP проверяет, например). Эту соль забирает не веб-приложение, а некий кэш в памяти (демон), а уже приложение получает его у демона и все рады. Получается, что даже физический доступ к серверу с выключением и переносом в другое место (с другим IP) не дает злоумышленникам или госструктурам доступа к паролям.
Тут вы неправы
Извините, не соглашусь.)
Чем соль «1937569admin» лучше «193756984938»? Добавление имени пользователя только лишь уменьшает длину той «эффективной» части соли, которая формируется случайно. А если мы в любом случае генерируем соль, то зачем нам усложнять алгоритм и дописывать к ней логин пользователя, когда проще (и правильнее) саму соль увеличить на несколько байт?
Делаем отдельный сервер
ОК, сделали.)
Злоумышленник находит уязвимость, заливает на веб-сервер шелл, заходит под привелегированной учетной записью… После чего внимательно изучает, с какого там внешнего сервера приходит соль и к какому порту нужно подключаться, чтобы ее получить.
Другой вопрос уже, что многие злоумышленники могут посмотреть на эту навороченную конструкцию и просто слиться, ибо не хочется это все разматывать. Но если хакер решит заняться делом всерьез — внешний сервер ничем не поможет.
лишь уменьшает длину той «эффективной» части соли
Это вы с чего взяли? Я не могу добавить к хэшированию user@mail.com и половину какого-нибудь рассказа, что ли? Запросто! И она не нужна разная для всех юзеров тогда, потому, что если вспомнить, для чего предлагают использовать соль — сделать все хэши разными. А эту задачу у нас выполняют логины.
Злоумышленник находит уязвимость, заливает на веб-сервер шелл, заходит под привелегированной учетной записью…
В таком случае ничего не поможет. Вообще. Мы не эту тему обсуждаем. А тему хранения разных солей отдельной колонкой в той же базе юзеров.
А чем 100 байт соли и логин лучше 120 байт или 150 байт чистой соли? Экономия на одном столбце таблицы БД?
Не требуется генерировать каждому свою соль. Соли не утекают злоумышленнику вместе с базой.
Первое, ИМХО, несерьезно: генерация соли почти не требует ресурсов.
Со вторым согласен, но для этого нет никакой необходимости использовать логины: достаточно хранить соль отдельно от БД.
Потому что для того, чтобы узнать «соль» в таком случае даже не нужно будет лезть в базу. А так да, вполне можно.
Вы утверждаете, что база намного лучше защищена, чем доступ по ssh, например? Почему же именно базы и утекают? Тогда можно и плейном хранить, если главная дверь не заперта.
Базы часто утекают как раз из-за получения доступа к самому серверу через уязвимости различного ПО. А получив доступ к файловой системе не составляет труда прочитать конфиги приложений с паролями доступа к БД. Но это всё абстрактно, есть доступная аналитика некоторых исследователей по разным видам уязвимостей и их популярности.
Зря автор не упомянул конкурс P-H-C и его победителя — семейство алгоритмов Argon2.
Возникает много вопросов:
Растяжение представляет собой итеративный, или рекурсивный, алгоритм, который раз за разом вычисляет хэш самого себя, десятки тысяч раз (а то и более).

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

Не понятно чем это обосновано. Соль нужна чтобы по радужным таблицам не найти хэш. В редких случаях когда соль не доступна, при брутфорсе может быть и имеет смысл на жизнь то что вы говорите. Но при этом надо понимать, что стоимость исследований эффективности различных методов генератора случайных чисел затребует достаточно много человекочасов и скорее всего станет нерентабельной. Так же, хотелось бы увидеть код, которым вы сгенерировали картинку для rand(), так как рисунок больше похож на ошибку в программе, не может каждое 30 значение функции rand быть 100% предсказуемым в общем случае.

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

Тоже не понятно, откуда эта цифра и для какого алгоритма? Почему не 16 или почему не 256? Опять же каких символов? (a-z или 0x00-0xFF),
На примере того же md5 в радужных таблицах сейчас редко запись для пароля длиннее 10-12 символов. (псевдослучайных)

ждать не менее секунды между каждой попыткой.

тоже сомнительный совет, откуда эта цифра?
Я как пользователь, если буду ждать секунду пока мой пароль будет проверяться, успею три раза уйти. Почему не 100 мс? Это уже будет не сотни миллионов паролей в секунду для перебора, а всего 10 в секунду.
знать точное количество итераций, поскольку любое отклонение будет давать другой хэш;

Слишком просто вычислить.
Достаточно знать свой пароль.
Алгоритмы MD5 и SHA-1 уже не обеспечивают достаточно высокой надёжности с точки зрения вероятности возникновения коллизий (см. Парадокс дней рождения).

Опять же зависит от стоимости информации. Я не отрицаю что в SHA-256 вероятность коллизии меньше чем в SHA-1, но и в MD5 и SHA-1 она крайне мала.
в парадоксе дня рождения всего 365 вариантов значения и 23 человека (6%)
в MD5 вариантов уже 3,4 × 10^38. т.е. даже если все 7 миллиардов человек зарегистрируются, вероятность коллизии будет очень мала и по большому счету ничего не даст. Даже в радужных таблицах вероятность коллизии будет на мой взгляд очень маленькой.
Для примера у меня 80 000 000 записей MD5, больше 4 байт коллизия бывает крайне редко.
Например, наш арсенал средств защиты относительно недавно пополнился так называемыми функциями губки.

Минус хэшей произвольной длины в том, что мы знаем у каких пользователей пароль короткий, а у каких длинный. И зная длину пароля, можно сразу начать брутфорсить только администратора с самым коротким паролем.
Всегда считал, что подсказки пароля (или вообще использование ответа на подсказку вместо пароля) серьезной дырой в безопасности и терпеть ненавижу, когда какие-либо системы или сервисы предлагают и даже требуют заполнения этого поля, отказываясь продолжать работу! ИЧСХ, таких систем и сервисов до сих пор over 9000, даже среди вполне серьезных компаний!

Это же надо было кому-то когда-то додуматься до такой идиотской мысли, а другим ее повторить! А чего сразу тогда не выводить, как в «Кто хочет стать миллионером?», 4 варианта ответов и 3 опции: звонок админу, помощь суппорта и 50/50?! Можно пойти еще дальше — задавать уточняющие и наводящие вопросы… Не, ну а чо?

Считаю, что те, кто применяет механизм подсказок, а особенно тот, кто придумал эту идею, достойны всеобщего презрения и порицания, за натуральную диверсию и подрывную деятельность в вопросах информационной безопасности!
Надо было просить вводить паспортные данные и восстанавливать пароль походом в офис? :)
Зачем же? Для восстановления пароля есть и другие стандартные, более надежные и проверенные временем способы: через электронную почту, телефон или через любой другой альтернативный канал связи.

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

А подсказка — это вообще не механизм восстановления пароля, и даже не механизм защиты, а совсем наоборот — это механизм понижения стойкости защиты и вообще дыра в безопасности.
Поколение 2000-х? :) Механизм восстановления по секретному вопросу использовали эти самые почтовики. Ну а про мобильные тогда вообще мало кто знал, тем более об автоматизированной рассылке смс по ним
Да не, постарше буду. :)

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

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

Причем, по своему опыту знаю случай, когда сервис даже не дает возможности изменить уже заданный ранее ответ на подсказку. Т.е. задал один раз и все, ни шагу назад! И это современный доменный регистратор! Доменный регистратор, Карл!!!

Да что далеко ходить, даже в современной венде используется этот уязвимый механизм подсказок, хоть и наравне с другими механизмами. Но мы ведь прекрасно понимаем, что стойкость системы определяется ее самым слабым звеном…
Долго можно спорить и разбирать каждый отдельный случай. Кто-то тянет этот функционал по привычке, винда просит ответ для локального аккаунта, который, я даже не представляю, как можно восстановить иначе? Ну а если смущает безопасность, то всегда можно ввести какой-нибудь мусор на 500 символов, что я собственно сам и делаю — в keepass для таких сервисов храню как сам пароль, так и рандомный хеш в качестве ответа на секретный вопрос :)
И это правильно, но не каждый среднестатистический пользователь до этого догадается, скорее вообще не придаст должного значения, вот если бы ему прямо говорили «задайте резервный пароль», еще куда ни шло… :)

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

Логин является плохой солью, потому что он может повторяться для разных сервисов; если используется один и тот же пароль, это будет заметно.

Интересно, что рекомендуется использовать bcrypt (не самое новое решение) и tweakable encryption (достаточно свежий подход). На самом деле bcrypt хорош только против взлома на GPU, на более продвинутых архитектурах он будет не сильно лучше PBKDF2 с тем же числом итераций.
Стоило в названии статьи указать, что речь исключительно про PHP, например «Риски и проблемы хеширования паролей в веб-приложениях PHP»
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Информация

Дата основания
Местоположение
Россия
Сайт
team.mail.ru
Численность
5 001–10 000 человек
Дата регистрации

Блог на Хабре