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

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

Если у вас есть пользователи и они авторизуются по паролю, я предлагаю еще раз посмотреть на свежие рекомендации от таких организаций как National Institute of Standards and Technologies и National Cyber Security Centre.

В частности, требовать ротации паролей уже не модно. И требовать определенных символов в лучших традициях анекдота про «1ГРЕБАНАЯрозоваяроза» тоже. Давайте пробежимся по основным тезисам и попробуем сделать пользователям удобнее и безопаснее.

Аутентификация не бинарна


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

Идеально доверенный пользователь сумел верно ввести пароль и заходит с авторизованного устройства. Чуть меньше доверия пользователю, который зашел с доверенного устройства, но ошибся при вводе пароля. И совсем плохо, если пользователь верно ввел пароль, но устройство недоверенное, второй фактор не подтвержден и IP принадлежит выходной ноде Тора. Вот в третьем случае пора дергать рубильник с надписью «Аларма! Волк украл зайчат!».

Наша задача, как людей предоставляющих сервис, сделать людям удобно, безопасно и не очень больно, если они ошибаются. Поэтому стоит расставить определенные признаки аномальной активности по порядку, чтобы включать те или иные дополнительные меры защиты аккаунта. Например, после 3-5 неверного ввода пароля предложить пользователю пройти CAPTCHA. Да, ее все ненавидят, но большинство пользователей с ней не столкнется. А те, кто понизил свой рейтинг доверия просто немного замедлятся перед очередным вводом пароля. Зато мы отсечем автоматические атаки на перебор пароля.

Не надо ограничивать максимальную длину пароля



Длинные пароли безопаснее. Дайте пользователям их использовать.

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

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

Да, есть крайне странные сервисы, которые считают, что и 12 символов хватит, а значит остальные 28 можно спокойно отрезать и проверять хеш только первого фрагмента. Не знаю, что за пораженный разум до такого додумался, но подобным нередко страдают те же банковские организации. Не делайте так. Если пользователь хочет использовать кусок из Иллиады пополам с фрагментами текстов группы Кровосток — пусть использует.

Убедитесь, что любые ASCII символы допустимы


Есть определенные проблемы со спецсимволами. Например, использование "{}/\" или других подобных символов может быть потенциально недопустимым в некоторых ситуациях. Скажем, фигурные скобки могут ломать валидный JSON и вызывать падение обработки пароля. Или символ апострофа, который может использоваться в SQL-инъекциях. Да, форма ввода пароля тоже может быть входными воротами для атаки.

В теории вы могли бы просто запретить использование подобных символов, чтобы сделать себе проще. Но тем самым вы снизите энтропию пароля пользователя и сделаете ему неудобно, если пароль генерируется автоматически. Придется подбирать определенные паттерны для исключений. Опять же обратимся к Марксу NIST:
Все печатаемые символы ASCII [RFC 20], включая пробел, должны быть допустимыми для ввода в качестве пароля. Символы Unicode [ISO/ISC 10646] также должны быть допустимыми.

Да. Все верно. Это ваша головная боль и дополнительное тестирование. Но если пользователь хочет использовать ???? ?????? ?????? или ???? ??? ?????? ???????? — дайте ему это сделать. Или добавить символ буррито в пароль для криптостойкости. Имеет право.

А еще отстаньте от пользователя с требованиями использования специальных символов. Да, вот просто не трогайте его. Пусть использует, что хочет. Исследования массовых утечек говорят о том, что люди все равно используют дурацкие замены со спецсимволами, что совершенно не улучшает ситуацию. В частности Microsoft пишет:
Большинство людей использует однотипные паттерны, например, заглавная буква в качестве первого символа, спецсимволы и цифры на последних двух позициях. Киберпреступники знают об этом и настраивают свои атаки с перебором по словарю с учетом типичных замен, таких как «s» на "$", «a» на "@" и «i» на «l».

Да-да, тот самый Microsoft из-за которого миллионы людей каждый месяц придумывают новый пароль, не совпадающий с предыдущими, содержащие спецсимволы и буквы в разном регистре. Именно они в своих гайдлайнах теперь пишут «Eliminate character-composition requirements».

Ведь в итоге, типичные утилиты вроде cain and abel, hashcat, john the ripper могут подобрать пароль в течение нескольких часов или даже минут на типичной видеокарте, если использовалось стандартное словарное слово и типичный паттерн замены.

Не используйте подсказки для паролей


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

В 2013 году у Adobe утекла база с паролями. Зашифрована она была криво, но самое неприятное, что она содержала подсказки для восстановления, над чем и не преминул поиздеваться Рэндал Манро в xkcd.
Того же мнения придерживается NIST, не рекомендующий хранение подсказок в любом виде. Забыл — восстанавливай через почту со всеми дополнительными проверками.

Снизьте нагрузку на мозг пользователя


National Cyber Security Centre выпустил крутую инфографику. Позволю себе процитировать небольшой фрагмент:

Обратите внимание, что основная проблема с паролями связана с тем, что хороший пароль случаен и его почти нереально запомнить. Если сервисов много, то пользователь почти неизбежно будет использовать один и тот же пароль везде, где можно. Особо продвинутые сделают что-то вроде «myp@ssword_habr.com». Естественно, что компрометация пароля в одном месте автоматически ставит под удар аккаунты во всех остальных сервисах.
Поэтому, дайте пользователю использовать менеджеры паролей. Да, это как специальный кошелек для банковских карт, который позволяет потерять их одновременно. Но тут надо понимать, что компрометация оффлайн хранилища паролей — довольно редкая ситуация, в отличие от компрометации одинаковых паролей на разных ресурсах. Менеджеру паролей не нужно быть идеальным. Ему нужно быть лучше, чем однотипные пароли везде. Не будьте как некоторые нехорошие сервисы, которые блокируют возможность вставки пароля в поле из буфера обмена. Это явно заставляет пользователя отказаться от менеджера паролей и использовать слабый вариант.

Второй пункт говорит о том, что не надо заставлять пользователя менять свой пароль, если нет явных признаков его компрометации. Это лишь мотивирует его использовать паттерн с одним и тем же паролем. Гораздо лучше поднять тревогу, если пароль всплывет в одном из многочисленных словарей утечек. Естественно, что нельзя давать пользователю создавать пароль, который уже попал в словари.

Выводы


  1. Будьте добрее к пользователю. Не надо заставлять его придумывать типовые паттерны и делать глупости. Стандартные привычные требования прям подталкивают его к этому. Просто соблюдайте несколько пунктов:
  2. Используйте аутентификацию по ключу вместо паролей там, где это применимо.
  3. Не давайте пользователю использовать пароль, если он есть в словарных базах. Неважно, он их туда слил или кто-то еще.
  4. Сообщайте пользователю, если его пароль появился в словарных базах. Поднимайте тревогу и требуйте второй фактор при следующем входе. Скомпрометированные пароли будут применены почти сразу.
  5. Требуйте определенной длины паролей и не препятствуйте, если пользователь хочет действительно длинный пароль.
  6. Убедитесь, что вы допускаете любые символы в качестве пароля.