Чаще всего, вопрос решается относительно просто. Если пользователь ввел несколько раз неправильно пароль, его учетка блокируется на какое-то время. Альтернативное решение — выводить капчу. Сразу, или после нескольких неудачных попыток. Ну, и не забудем про 2F авторизацию, которая почти неуязвима. Казалось бы — профит! Но, не все так радужно…
Давайте рассмотрим некоторые проблемы описанных решений:
Временная блокировка — учетка пользователя временно заблокирована и он не может попасть в систему. Реальный пользователь в период атаки испытывает душевную боль и терзания. Он не может попасть в систему. И скорее всего нагружает ваш саппорт. А самое интересное, что, возможно, в этом и есть цель атакующего.
Капча — относительно неплохое и эффективное решение. Правда доставляет неудобство пользователю, требуя вводить что-то там дополнительно. Достаточно “неприятно” встраивать в дизайн. Ах да… еще эта штука, в зависимости от реализации, может быть подвержена DoS атаке.
2F авторизация — Все замечательно. Правда… чаще всего это штука опциональная. Включить ее для противодействия атаки не выйдет. Она или есть, или ее нет. А на некоторых ресурсах вводить 2F авторизацию, скажем так, по воробьям из танка стрелять.
Я стараюсь создавать удобные и надежные сервисы. Поэтому, я решил немного напрячь мозги. И вот, что вышло.
Если вы пользуетесь почтой, например mail.ru, и у вас установлена 2F авторизация, то возможно уже замечали, что 2F авторизация запрашиваться только для нового “устройства” при первом входе. Далее, устройство считается доверенным. И нужно просто вводить логин и пароль.
Удобная штука. Юзерфрендли, так сказать. Реализуется это двумя токенами. Первый идентификатор “устройства” (определим как devid), а второй сессионный (определим как session). Devid, в отличии от session не теряет актуальности даже после завершения сессии пользователем. Он передается при следующей попытке входа, и если логин/пароль верный, а также devid доверенный, 2F уже не запрашивается. Но, если очередная попытка входа оказалась неудачной, токен devid тут же протухает. И теперь нужно пройти полный путь авторизации.
За основу была взята эта парадигма. Т.е. ввести токен devid, который будет выдаваться постоянно, при любом ответе WEB-ресурса, конечно, если его не было в запросе.
Для случая 2F авторизации был, фактически, реализован вышеописанный алгоритм. И сразу все стали довольны. Т.ч. его детально рассматривать смысла нет. А вот «навороты», лучше рассмотреть на схеме, с пояснениями:
Даже, если не установлена 2F авторизация, но вход был успешным, то токен devid помечается как доверенный. Казалось бы, смысла особого нет делать это без 2F авторизации. Но, все чуть хитрее. Если мы знаем, что devid доверенный, т.е. с него был успешный вход, мы как минимум предполагаем, что именно с этого устройства входил реальный юзер. Это очень важная информация, которую использует описываемый алгоритм в своей работе в режиме отражения атаки.
Была принята стратегия: любая авторизация может происходить только при наличии валидного токена devid. Валидный devid отличается от доверенного тем, что он еще НЕ доверенный, т.е. с него не было успешных входов, но система готова обрабатывать с ним запросы на авторизацию. На один валидный токен количество попыток ограничено N раз. Если происходит ошибка авторизации более N раз подряд, токен помечается как “скомпрометированным”. Он переносится в отдельный журнал со статистикой подбора. Запросы с его участием продолжают обрабатываться, но… залогиниться с ним уже нельзя. Все, что происходит — накопление статистики активности.
Так отбиваются самые глупые атаки. Например, если атакующий, игнорируя devid, пытается логиниться в систему или если он не смог понять логику работы devid (откуда ему знать сколько дается попыток логина с одним и тем же devid?), его запросы терминируются.
Собственный фронт знает, что после N раз неуспешных попыток входа с одного devid, он уже “протух”. Теперь нужно получить новый токен, перед очередной попыткой логина.
Казалось бы, что за глупость? Фронтом отрабатывать попытки входа… но, как я уже сказал выше, все хитрее. Если пользователь работает через штатный фронт вероятность того, что он действительно пытается атаковать систему ничтожна мала. В паре с системой контроля сложности пароля при регистрации пользователя это совершенно бесперспективно. Скорее всего, реальный пользователь, реально пытается вспомнить свой пароль.
Ну так в чем же хитрость? В том, что на бэке мы генерируем те самые валидные devid с определенным лимитом по времени. Например, не более 1000 шт в минуту. Если вдруг этот лимит превышен, врубается режим атаки. И тут либо можно пойти радикально и прекратить эмиссию devid на какое-то время, что резко охладит пыл атакующего, либо уменьшить объем генерации валидных devid. А можно, включить ту самую капчу, для всех валидных, но недоверенных devid.
Таким образом получается гибкая система контроля и управления атаками. Образуются надежные метрики по которым может срабатывать мониторинг поднимая тревогу. Накопленную статистику можно преобразовывать в правила блокировки и т.п.
А дружелюбной система является потому, что те пользователи, которые ранее входили в нее, т.е. имеют доверенные devid даже не заметят атаки. Они будут пропускаться системой без проблем.
Вот теперь профит. Данный алгоритм весьма неплохо зарекомендовал себя на ресурсах с весьма высокой нагрузкой. Были, в том числе, попытки DoS на сам алгоритм, но и тут он показал себя достойно.
Комментарии (17)
Revertis
14.11.2018 15:23+1Временная блокировка — учетка пользователя временно заблокирована и он не может попасть в систему. Реальный пользователь в период атаки испытывает душевную боль и терзания.
Что за дурацкий выбор блокируемого. Почему нельзя заблокировать айпишник атакующего вместо учётки атакуемого?Belibak
14.11.2018 16:01+4Потому что nat?
rpiontik Автор
14.11.2018 17:03Да. Верно. Nat. Но и еще потому, что нужно понять какой ip блокировать. Статистика нужна. Часто такие атики идут через проксики. Про ботнеты я молчу. Так можно пол сети перестрелять… а толку недобиться.
Revertis
14.11.2018 17:081. Вы блокируете страницу авторизации целой подсети, которая за натом.
2. Пользователи этой подсети ругаются с провайдером.
3. Провайдер находит атакующего и даёт ему по шапке.
4. Все в выигрыше.rpiontik Автор
14.11.2018 17:50+1Эм… :)) как я в этих случаях говорю — я рад, что у нас есть такие ответственные граждане. Но очень жаль, что я их живыми не видел…
Belibak
14.11.2018 18:19+12. Пользователи этой подсети
ругаются с провайдеромуходят и больше не возвращаются, потому как — там логин сломан.
Slihs
15.11.2018 09:06В статье не сказано преимущества доверенного токена перед просто валидным. Если его нет, то он бессмысленен, если оно все же есть (напр. больше попыток на вход и т.д.), то тогда еще вопрос — доверенный devid как-то привязывается к пользователю или нет? Если не привязывается — что атакующему мешает сделать его доверенным через вход в его собственный аккаунт и вся защита сходит на нет. Если привязывается, то это порождает множество других проблем — усложнение системы, сложность входа с одного устройства разных пользователей и т.д.
Вообще, это скорее не защита от брута, а защита от доса через брут, т.к. в плане усложнения перебора здесь ничего нет (любые фронтенд фичи легко обходятся естественно), а по факту только увеличение количества потенциальных слабых мест, как с примером выше. Обычно защиты от брута выглядят гораздо строже.
Например, хитрость с превышением лимита и т.н. «режимом атаки» легко обходится тестовыми запросами для вычисления лимита. Сам лимит в 1000 в минуту не адекватен (понимаю, что для примера, но пример не очень):
- Если лимит привязан к юзеру — ничто не мешает атакующему брутить параллельно миллионы юзеров и тут даже 10 попыток в минуту может хватить чтобы сбрутить нереальную кучу юзеров/паролей.
- Если лимит привязан к IP — ботнеты в помощь
- Если лимит ни к чему не привязан — получаем сразу DoS всей системы выдачи devid и больше никто с нового девайса не зайдет. Включение капчи и любые другие ужесточения все равно убьют на корню всю задумку «дружественной» защиты
Таким образом, защита от брута получается от слова «никакая». К сожалению, ничего лучшего 2FA в этом плане пока не придумали, как вы и сами заметили. Тогда весь смысл вашей задумки все равно теряется. А приведенный пример mail.ru как раз реализован в 2FA, где ему и место.
Также ваша задумка «дружественной» защиты подразумевает, что пользователь не узнает, что на его аккаунт идет атака. Это тоже неверное решение. Если его аккаунт брутят, значит он скорее всего куда-то утек (либо взломаны его другие аккаунты на этом имейле, либо еще какая-то уязвимость используется), а в этом случае надо большими красными буквами писать об этом пользователю, даже если это не влияет на его текущую сессию. Надеюсь вы понимаете почему.
Если все же целью является только антидос логина, то предложу еще один вариант обхода. Я так понимаю, что при логауте пользователя сессия разрушается, но devid сохраняется как доверенный. Есть еще один тип атак — CSRF. Большинство сервисов имеют login/logout CSRF и не считают это за уязвимость (почем зря). Однако через логаут и последующие N некорректных логинов… ну вы поняли :) Вот такой вот CSRF DoS, причем массовый (не направленный на конкретного юзера).
А все это ради чего — неведения пользователя, что его атакуют? Итак пользователи слабо осведомлены о самых базовых аспектах ИБ, так мы им в этом еще поможем. Снижение нагрузки на саппорт? Отправляйте в FAQ, где жирными буквами будет написано, что если вы не можете войти в систему и это не вы превысили количество попыток — то ваш аккаунт пытаются взломать, ну и кучу советов по этому поводу, включая 2FA.
Мнимая безопасность часто хуже ее отсутствия… Хотя вопрос с антидосом логина считаю открытым, возможно и есть более подходящее решение.rpiontik Автор
15.11.2018 09:16Я одобрил ваш пост, потому, что вы потратили уйму времени на его написание. Пожалуй по объему он приблежается к статье. Но прошу вас потратить еще немного на прохождение ваших кейсов по схеме.
Да, основная задача — дать «друзьям» возможность пользоваться ресурсом даже в период атаки. Да, в зависимости от стратегии реагирования, пользователи с новых устройств будут получать, например капчу. Но «друзья» страдать будут минимум или вообще не будут. Капча будет включена в период атаки, и автрматом выключится при нормализации ситуации. А атака захлебнется из-за таких включений. Просто смысла не будет троллить.
Не забудьте о сборе статистики. Бороться с атакой, в любом случае, можно только комплексно.
Как я ответил выше, некоторые решения я оставил за «скобками». Уверен, что развить данную идею в части валидации токенов можно серьезно. Собственно на боевых серверах это так и сделано.
Что касается 2F я уже описал ее недостатки. И подчеркну еще раз, я за ее имплементацию там где это нужно.
Ну и посылать в faq пользователя… ну это моветон. А если ему 78 лет?Slihs
16.11.2018 05:20Но прошу вас потратить еще немного на прохождение ваших кейсов по схеме.
Я изучил схему еще вчера, но ответов на мои вопросы там не нашел. Я думал просто, что вы случайно или намеренно не упомянули некоторых деталей. Жаль что вы не захотели отвечать на эти вопросы, придется мне отвечать за вас.
Таким образом, вопрос про необходимость доверенного токена отвечен вами как — «нафиг он не нужен», потому что если выбросить элемент алгоритма «Is dev untrusted?» — ничего не изменится в работе алгоритма.
Капча будет включена в период атаки, и автрматом выключится при нормализации ситуации. А атака захлебнется из-за таких включений
Послать 1000 запросов в минуту — это захлебнуться? Чтобы атакующему выполнить дос-атаку на процесс логина ему не нужно проходить капчу. Пользователю же чтобы войти в систему это будет нужно. Ну и кто захлебнется из них? Ведь как я понимаю по вашим пространным ответам вы и не пытаетесь реально бороться с брутом, наоборот вы смягчаете защиту от брута ради «друзей».
А теперь ход конём: атакующий заранее постепенно генерит мильёны devid, а затем спокойненько себе брутит в свое удовольствие, попутно блокируя выдачу новых devid для всех остальных :) Не нашел где в вашей схеме есть противодействие такому поведению. В итоге: и защиту смягчили и «друзей» не спасли от доса. За двумя зайцами погонишься… Информационная безопасность это всегда баланс: нельзя просто так взять и повысить удобство, не пожертвовав безопасностью.
Ну и посылать в faq пользователя… ну это моветон. А если ему 78 лет?
Ок, погорячился, считайте это за шутку или моветон, как вам угодно. По существу: жирными буквами надо писать чтобы включали 2FA, если не хотите страдать от брута.
Вывод: либо нормальная защита от брута, либо 2FA. И слоган — хотите стать нашими друзьями — включайте 2FA! Вот и все, не нужно ничего городить лишнего. Я думаю любой, даже самый тупой пользователь при первой же невозможности залогиниться с нового устройства, если ему написать что при включении 2FA такого не будет — с радостью включит его.
Здесь ситуация походит на криптографию — постоянно возникают люди, думающие, что они знают что-то лучше многолетних изысканий великих криптографов, посвятивших этим самым изысканиям всю свою жизнь. Хотя я в целом рад стремлению автора сделать что-то лучшее, но все же надо более внимательно подходить к таким вопросам, тем более что вашими советами могут неправильно воспользоваться другие люди. Нельзя скопировать то, что было сделано для 2FA и применить это без этой самой 2FA. Если вы во всем этом надеетесь еще и на Security Through Obscurity, то когда-нибудь вы (или тот, кто вам доверился) за это поплатитесь нехилым сливом, и может быть вспомните мои слова. Но все же советую одуматься сейчас, чем кусать локти потом.rpiontik Автор
16.11.2018 08:05Еще раз, внимательно, пересмотрите схему. Еще раз, внимательно, прочтите комментарий мой вам и комментарии ранее. Вы найдете ответы на свои вопросы.
Спасибо!Slihs
16.11.2018 21:28Еще раз внимательно перечитайте мой предыдущий комментарий, там я за вас ответил на вопросы, на которые не смогли ответить вы. Жаль, что вы не умеете аргументированно обосновывать свою точку зрения, особенно в деталях, ведь я надеялся, что хабр для этого и нужен, чтобы иметь возможность сообща приходить к наиболее полному и верному решению. Тот комментарий был для того, чтобы предостеречь доверчивых людей от использования вашей схемы без 2FA, т.к. вы не смогли подтвердить или опровергнуть мои опасения о безопасности такой схемы.
P.S.
Кстати, концепцию т.н. «доверенных» токенов, можно использовать раздельно от вашей основной схемы валидных/невалидных devid, как это делается множеством сервисов. Напр. при первом успешном входе с недоверенного токена отправлять ссылку на имэйл, и при подтверждении считать его доверенным. Также это часто делают для тех юзеров, у кого отключена 2FA через СМС/OTP-токены. Но по факту это и есть 2FA, просто вторым фактором выступает не СМС и OTP, а email. И опять же не надо городить никакой другой «дружественной» мути, снижая безопасность, ведь этого уже достаточно.
AGARTY
15.11.2018 23:34Я для своей CMSки реализовал аналог fail2ban. При определенном количестве не верных попыток блокирую на определённое кол-во минут. Например 5 не правильных логинов — блок 30 минут. Еще вводил нарастающие паузы. Например после третьего не верного ввода в течении 5 минут, каждый последующий уходил в «паузу» на 1 секунду дольше предыдущего.
Но потом отказался за ненадобностью. Теперь прячу админку от чужих глаз на другом поддомене (алиасе) клиентского сайта, и судя по статистике никто кроме меня и клиентов в административную часть не заходят.
Но Вашу схему возьму на вооружение, посмотрю пригодится или нет.
RouR
А храните их где? Я бы снял нагрузку на их прегенерацию и хранение добавлением поля devid_sign (шифрование), по которому и проверять валидность. А счётчик неуспешных попыток положил бы в redis, с устареванием по времени.
rpiontik Автор
Да. Вы правы. Некоторые моменты я оставил за «скобками». Реализация не так важна как идея. Ну к примеру, очередной devid генерируется с учетом ip запроса. В хеше включен. И с другого он уже не валиден, если не достоверный. И срок жизни имеет. Иначе атакующий может накопить их а затем атаковать. Это уже тонкости зависящие от потребностей.