Как усилить защиту паролей «12345» от brute-force атаки

Объект: веб-форма входа в систему.
Дана задача: усилить защиту аккаунта пользователя от подбора простого пароля к его аккаунту, используя минимум средств.

Что такое минимум средств? Это не использовать таблицы-справочники для блокировки по IP-адресу и User-Agent. Не использовать лишние запросы к системе, не захламлять систему авторизации лишними циклами.

И, выполнить совершенно волшебное требование — даже если бот введет нужные логин и пароль… не дать ему войти, а вот реального пользователя впустить.

Можно ли так сделать? В теории, конечно, нет. Но в практике, в частном порядке и при определенных условиях, как оказалось, весьма возможно.
Приглашаю под кат за подробностями.

Итак, предположим, что, логин у нашего пользователя «test», а пароль «12345». Мерзкий бот подключил свой словарь сгенерированных паролей, и готов работать со скоростью 700 паролей в секунду. Он знает, что логин пользователя — «test». Ситуация аховая: пароль «12345» будет вычислен за очень малое время. Пользователь, тем временем, открыл сайт и начал вводить логин и пароль в веб-форму логина.

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

Магия будет заключаться в третьей переменной, которую следует «приклеить» к паре логин-пароль. Я назвал ее touch.

Каждый раз, когда кто-то получает (внимание: получает, а не запрашивает!) логин-пароль, дата «touch» для пользователя «test» обновляется на текущую дату-время:

login/password/touch: 'test', '12345', '2014-12-13 14:00:00'.

Предположим, что бот начал первую итерацию и предложил пароль «1» для логина «test» в '2014-12-13 15:00:00'. Cрабатывает контроллер login_check, который читает из базы данных пару логин-пароль, которую никто не «трогал» целых 2 секунды! Откуда вообще эти 2 секунды?! Об этом будет дальше.

Такая пара логин-пароль находится. Разница между последним «touch» и текущим временем — 1 час. Поэтому запись успешно возвращается на наш запрос.

Сначала пара логин-пароль сличается и login_check приходит к выводу, что «test/12345» не равно «test/1». Контроллер возвращает «auth error». А затем дата «touch» для пользователя «test» обновляется на текущую: '2014-12-13 15:00:00'.

Бот приступает к следующей итерации: пробует пароль «2».

Скорость работы бота измеряется микросекундами. Он пытается авторизоваться сразу же: в '2014-12-13 15:00:00'.
И тут вступает в действие наш алгоритм — условие по параметру «touch» уже не выполняется. 2 секунды еще не прошли. Fail.

Модифицированный нашей логикой контроллер «login_check» не может получить пару логин-пароль.
Запись существует, но ее дата «touch» еще слишком «свежая».

И она она уже не попадает в выборку. А раз такой пары логин-пароль нет, то контроллер ответит боту «auth error».

Бот не сдается, продолжает подбор и, наконец, приходит к правильному паролю «12345».
Вероятность, что именно текущая попытка вернет успех — крайне и крайне мала. 1/700 на каждую попытку входа! То есть, если раньше было 1:1, то теперь 1:700. И чем быстрее бот, тем больше вероятность, что его ждет fail.

В итоге только очень малая часть паролей будет действительно проверена. Остальные получат ложные срабатывания, даже если они будут верны.

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

Когда пользователь видит ошибку авторизации, он часто переписывает пароль заново. Даже если пароль он только что вбил сам. Даже если пароль подставлен автоматом из password-manager. Я делал это еще до того, как применил свою систему защиты простых паролей.

Да, я обещал рассказать про две секунды. Рассказываю:
Две секунды это оптимальное время, за которое пользователь проводит операции по корректировке данных и совершает следующую попытку входа. В эти две секунды пользователь укладывается полностью. Если пользователь не уложился — он всегда может повторить попытку и за это время действие touch уже наверняка аннулируется.

В заключение.
Что будет если бот узнает о 2-секундной задержке? Если применить наши тестовые данные, это значит, что эффективность бота снизится: всего 1 попытка подбора пароля вместо 1400.

P.S. Очень хочется услышать критику, потому что система уже внедрена в один проект, и пока не создала ни одного тикета с проблемой доступа к системе.

Заранее спасибо.
Share post

Comments 52

    +11
    он всегда может повторить попытку и за это время действие touch уже наверняка аннулируется.

    Но если бот ещё активен, то не аннулируется и пользователь также будет видеть ошибку входа, верно?
      –3
      Да, верно. В данной схеме подразумевается, что если пользователь постоянно будет испытывать сложности со входом, он создаст тикет в поддержку, чтобы администратор ресурса принял меры.
        +13
        Если пользователь постоянно будет испытывать сложности со входом — он закроет сайт и найдёт менее глючных конкурентов.
          +2
          Если у пользователя на сайте что-то достаточно ценное, что его целенаправленно брутят, то никуда он не уйдёт.
      +16
      Кажется, в вашей системе бот может забанить любого пользователя.
        +7
        Особенно пикантной ситуация будет когда бот начнет долбить в юзера с логином admin :)
          +4
          Administrator, root и далее по списку. Параллельно.
            +6
            Вот поэтому у нас логин админа qfh1BmIbV3mQnvpJAMozhZQJTI3xldx1.
              +33
              … и пароль 12345.
                +1
                админский пароль qwerty
                  0
                  qwerty123, чтоб секьюрнее было
                    +1
                    админский пароль «GOD»
          +1
          пока не создала ни одного тикета с проблемой доступа к системе.

          А отслежено ли какое-то количество попыток подбора паролей ботами?
            0
            Нет, атаки на ресурс не проводились или мне о них неизвестно. Это небольшой стартап, и популярность у него небольшая.
            Пока могу сказать за живых пользователей: они не писали мне о проблемах входа в систему.
              +22
              Не смогли залогиниться, чтобы создать тикет.
            +2
            Боты проверяют обычно пароли в порядке их популярности и очень велика вероятность, что он в первую-шестую очередь проверит пароль 12345.
            • UFO just landed and posted this here
                +19
                Основная проблема только в том что очень тупые боты будут непрерывно перебирать пароли одного пользователя без остановки. Дело в том что в большинство нормальных сервисов после некоторого кол-ва неправильных паролей в течении определенного времени у одного пользователя будет требовать не только пароль, но и вводить сложную капчу (а может вообще заблокировать данную запись и требовать восстановления через почту/телефон). Поэтому боты не перебирают пароли у одного пользователя, а ходят по всей базе данных пользователей (её на форуме или почтовом сервисе, например, можно получить вообще в открытом виде) и подставляют каждому пароль 123. Причем ходят, естественно, под разными ипшниками. На следующий день они пойдут по всем пользователем, но с паролем 1234 (на самом деле это утрировано, они могут случайно выбирать из списка легких паролей и подставлять каждому «свой» пароль и запоминать результат). Через месяц-другой у ботов будут все аккаунты с легкими паролями, причем ни разу они не натолкнуться на лимит по времени или ип адресу сервиса, так все запросы будут очень распределенные по времени и ип.адресам.
                  –9
                  Спасибо за совет. Я обязательно обдумаю, как предотвратить эту ситуацию.
                  Думаю, малую часть пользователей можно защитить, если принудительно требовать от них смены пароля раз в две недели, например. И если бот не успел перебрать все пароли, ему придется начинать перебор заново, чтобы гарантированно подобрать пароль к конкретному логину.
                    +6
                    Сваливать свою работу на пользователя — дурной тон
                      +1
                      Не уверен что это хорошая идея:
                      1) Пользователям быстро это надоест, например принудительно менять раз в месяц даже на рабочем компе пароль для меня было весьма утомительно
                      2) Есть пользователи, которые могут месяцами не логиниться (и соответственно не менять паролей),

                      Вообще, все украдено для нас. Самый простой и довольно эффективный алгоритм защиты от перебора такой:
                      1) Все-таки заставлять пользователей не использовать совсем уж легкие пароли,

                      2) Ограничить кол-во попыток логирования для пользователя и ипишника (отдельно для каждого user'a и отдельно с каждого ip'шника) определенным числом за N минут, например не более 5 неудачных попыток входа за 15 минут, после требовать ввода сложной капчи и давать ещё 5 попыток, если пользователь ввел её успешно (ввод любой капчи это ещё не гарантия что это не бот из-за трудолюбивых китайцев с их сервисами ручных распознаваний капч, но распознавание миллионов капч все-таки весьма дорогое занятие, чтобы оно имело смысл),

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

                      Это позволит ограничить как ботов, перебирающих пароли сразу, так и тех кто перебирает по-немногу. Правда, проблема все равно остается если пользователь заходить часто, а бот перебирает достаточно медленно, тогда есть шанс что пользователь будет успевать вводить правильный пароль чаще чем бот израсходует лимит неправильных. Тут есть несколько вариантов:
                      1) Анализировать соответствие правильных и неправильных пользователей, если ипшники и юзер агенты и включена ли js или нет, всех кто входит под правильным паролем и под неправильным никогда не совпадает, включаем для пользователя капчу при каждом входе,

                      2) другой вариант, при входе правильного пользователя выводить предупреждение с каких ип адресов, когда и сколько раз были попытки входить в систему и показывать кнопку «это был не я»

                      3) придумать что-то свое…

                      P.S. Если есть желание помучатся, можно порыть в сторону анализа таких вещей как включен ли у пользователя javascript (например, отдавая ему хитрую, сгенеренную каждый раз заново, функцию javascript, устанавливающую хитрые ключи в скрытые поля форм), правильные ли user agent'ы и работа с куками, нет ли следов работы с прокси или ипишников совсем отличных от предыдущих ипишников регистрации и успешных входов и т.п. Соответственно, для подозрительных пользователей, показывать капчу или раньше или вообще сразу при вводе пароля.
                        0
                        А да, для полноты защиты, можно даже ограничить общее кол-во неправильных вводов пароля даже с капчей и потом требовать или восстановления пароля или ввода какой-то дополнительной информации. Например, если пользователь ввел даже с капчей 50 раз пароль неправильно, предложить ему восстановить пароль по email или ввести дату своего рождения/email/т.п. для дальнейших попыток ввода пароля.
                        +1
                        Это не вариант. Принудительная смена паролей приведеи или к ротации 2-3 паролей, или к постоянному забыванию паролей пользователями, т.к. больше 2-3 редко кто способен помнить.
                        Лучше сохраняйте все попытки логина в отдельную таблицу. Например
                        логин, IP, время
                        Тогда вы сможете анализировать с какого IP сколько раз входили и под каким пользователем. При превышении частоты входов можно начать требовать капчу.
                      +1
                      Обычно делают лимит на кол-во попыток логина в секунду. Это будет эквивалентно варианту, когда бот знает про двухсекундную задержку.
                        +1
                        Обычно делают капчу, которая активируется после нескольких (часто даже одной) неудачных попыток. Пользователю не влом будет ввести капчу, даже если его попросят её ввести при самом первом логине.
                        0
                        Использовать БД для контроля атак на пароли перебором это сильно! Разумеется, если в вышей системе больше 10 пользователей (людей).
                          0
                          Смотря что за БД. В данном случае хорошо бы подошли nosql key-value БД, в идеале in memory.
                            0
                            Верно но ещё бы лучше подошёл bcrypt с количеством раундов таким, чтобы считалось 2 секунды. Сразу для двух зайцев, так сказать.
                              +1
                              И шикарный ддос можно устроить. Если даже не выест весь процессор, то выест всю память процессами работающими по 2+ сек.
                          +2
                          Однако, какой простор для DDoS'а!
                            0
                            И чем быстрее бот, тем больше вероятность, что его ждет fail

                            да, а вероятность, что пользователь успеет попасть в интервал между аннулированием touch и следующей итерацией бота еще меньше
                              +6
                              Нормальные боты берут какой-нибудь популярный пароль и начинают перебирать юзеров. Так обходятся очень многие защиты (в том числе и ваша).
                                0
                                Удобно если пользователи где-то на виду лежат (как на форумах).
                                  +1
                                  Да, но на самом деле, имена пользователей ещё более предсказуемы, чем пароли, на мало-мальски крупном сайте можно гарантировано перебирать самые популярные имена и фамилии (olga, ivanov, petrov, olga1982 и т.д.), а так же основные популярные английские и русские прозвища, типа красава, cat. dog, mad dog и т.п. Плюс погуглив по сайту часто можно получить список пользователей (например, из ников авторов статей и комментариев). В целом, лучше рассчитывать что бот имена пользователей знает, даже если у вас сайт банка и каждего пользователя вы заставляете придумывать имя вроде dujhhj244.
                                0
                                Я бы добавил еще сессии для каждого кто пытается логиниться, причем ID сессии писать в куки, когда кто-то заходит на страничку с формой логина, при попытки логина запрашивать ID сессии из куки. ID Сессии еще бы хорошо привязывать к IP. Разграничение по сессиям позволит войти НЕ боту. Причем еще можно связать ID сессии и логин которые уже были авторизованы. И чем старее ID сессии с успешной авторизацией тем больше доверия к клиенту который пытается авторизоваться.
                                  +1
                                  А смысл? Боты прекрасно умеют менять ип адреса, посылать каждый запрос с нового ип адреса вообще не проблема, учитывая кучу бесплатных прокси и весьма умеренные цены на платные.
                                  +1
                                  Боты редко перебирают пароли к аккаунтам. Чаще аккаунты к паролям.
                                  Любого пользователя можно «забанить», долбить с частотой 2 сек можо даже из браузера.
                                    +4
                                    Сделайте уже двухфакторную авторизацию, и бот не зайдёт даже точно зная правильные логин и пароль.
                                    Вместо touch храните IP-адрес юзера. Адрес сменился со времени последнего входа — посылайте юзеру SMS или письмо с одноразовым кодом или линком для входа. Вместо адреса можно использовать привязанную к версии ОС и браузера куку, как это сделано у Гугла.
                                    И боты даже не будут пытаться подбирать пароли к вашим юзерам.

                                    Или ещё проще — сделайте вход через социальные сети, и пусть у них болит голова о безопасности пользователей.

                                    Тем более, если у вас стартап — зачем забивать себе голову распознаванием ботов, когда можно потратить это время на основную функциональность? Конечно, если ваш стартап не о распознавании ботов :)
                                      0
                                      Мой способ как раз и создан для того, чтобы не забивать голову. Он намного проще реализации входа через соц-сети или двухфакторной авторизации. Он не идеален, не является панацеей и не защитит высоконагруженные проекты. Он уменьшает вероятность подбора пароля, который может оказаться слишком простым. Перечислю видимые мне плюсы:

                                      • Быстрая реализация. Существующую регистрацию менять не потребуется: создаем свойство touch, добавляем его в условие выборки пользователя, и делаем апдейт touch при попытке проверки записи пользователя.
                                      • Детектирование проблемы. Хотя журналы учета попыток входа в систему не ведутся, пользователь сам напишет, что не может попасть в систему, а администратор проверит аккаунт и, с большой степенью вероятности, увидит трудолюбивый подбор паролей in real-time. Не всем нравится этот метод, но он лучше, чем совсем ничего или тикет «Здравствуйте, у меня уже украли аккаунт».
                                      • Бот может подбирать пароли на ресурсе, а его даже могут не замечать годами. Он с большой степенью вероятности не получит положительный ответ на правильную пару логин-пароль. Это может сбить его с толку, если он ведет обычный перебор паролей по словарю к заранее известному аккаунту пользователя (в комментариях уже подсказали, что можно делать перебор не паролей, а аккаунтов, и для такой ситуации это уже проблема).
                                      • Реализация не завязана на данные с клиента.


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

                                      Авторизация через соц-сети видится мне хорошей альтернативой способа защиты паролей. Но у этого способа есть два больших недостатка: не все зарегистрированы в соц-сетях (а некоторые не хотят использовать личный аккаунт для авторизации на сайте), и для каждой соц-сети потребуется делать свою реализацию входа.
                                        0
                                        Если пользователь сидит на пуле провайдера (а это обычное дело), то IP у него будет меняться очень часто.
                                        0
                                        Я для одной странички в случае неудачного пароля выдавал страницу только через 5 секунд. Поидее тоже должно мешать брутфорсить. Но в случае большого количества запросов на сервере будет висеть куча «пятисекундных» запросов. Что, думаю, не есть хорошо.
                                          –1
                                          Просто добавить соль при генерации пароля не судьба была в начале?
                                            0
                                            *хэша пароля
                                              0
                                              Вы все напутали. Речь идет о подборе пары логин-пароль для авторизации, а не о хранении хэша пароля в БД.
                                              Для авторизации приходят строки без всякой соли.
                                                0
                                                Да, пардон, от недосыпа видимо напутал.
                                              0
                                              Смотрели какя защита у сети стим, или у гуглопочты? Зная точно имя и пароль нет возможности войти в аккаунт (учитывают расстояние между ip и временем последнего входа, плюс привязка к устройствам)
                                                +2
                                                Это, как говорится, «security through obscurity».
                                                Как только злоумышленник поймет суть защиты (а это не проблема), он
                                                а) сможет подбирать аккаунты к паролям
                                                б) сможет блокировать чужие аккаунты. Просто так. Этакий банхаммер в руках любого пользователя.

                                                Сложные пароли эти векторы атаки нейтрализуют.
                                                  0
                                                  Я правильно понимаю, что если небольшой ботнет (из 10 компьютеров) будет подбирать пароль к пользователю ivan, то сам пользователь вообще не сможет зайти в систему, пока ботнет не будет остановлен, так как пользователю будет постоянно сообщаться что-то типа «auth error» потому что «две секунды» не прошли с момента последней попытки авторизации по этому логину?
                                                    0
                                                    Да. Пока аккаунт пользователя бомбардируется, пользователь-человек в систему не войдет.
                                                    0
                                                    у меня проверяется три параметра — логин, пароль, допустимый IP. если все три параметра верны — в систему пустит, если нет — ну, досвиданья.
                                                    ах, да, логи вебсервера читаются fail2ban, в случае нагления — мы считаем что пришел бот и с удовольствием пополняем коллекцию iptables
                                                      0
                                                      Ожидал увидеть, что с помощью javascript или формы на flash вы вычисляете скорость набора пароля пользователем. Что провели исследование, пользователь набирает пароль так, что функция от длины пароля и времени между нажатиями клавиш возвращает x1-x2 для людей, и y1-y2, z1-z2 для роботов.

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

                                                      Или что как-то развита идея OpenID или OAuth, где токены от стороннего провайдера, в случае подключения этого провайдера, используются для дополнительного подтверждения личности. Кто не подключил себе такую защиту — ставит себе сложный пароль. Представляю ситуацию так. Пользователь часто авторизован в сервисе, предоставляющем OpenID, пусть Яндекс, или OAuth, пусть Контакт. И пользователь подключает к своему профилю в вашем сервисе этих провайдеров, а в вашем сервисе ставим пароль 12345. Для успешного взлома надо знать уже три пароля. Пусть сессию с OAuth, пароль вашего сервиса 12345 кто-то отснифал, в силу отсутствия шифрования трафика. Но OpenID остался неприкосновенным — сработала защита на транспортном уровне.
                                                      А защита от подбора пароля 12345 строится в этой истории так: бот подбирает пароль 12345 к поставщикам OpenID и OAuth, они его банят с помощью их секретных механизмов защиты — бот не может пройти аутентификацию и вашем сервисе.

                                                      Думаю, сделаю такую защиту, когда-нибудь. И бота для неё напишу.

                                                      Only users with full accounts can post comments. Log in, please.