Работая над защитой интернет-магазина одного из клиентов, мы несколько раз столкнулись с любопытной brute-force атакой, противостоять которой оказалось не так просто. В основе её лежало простое до изящества решение, выделявшее атаку из рядов ей подобных. Что она собой представляла и как мы от неё все-таки защитились, читайте под катом.
Как вы знаете, «классический» brute-force — это атака методом перебора данных. Например, берутся известные учётные записи, и к ним подбираются по каким-то критериям пароли, либо генерируемые на лету, либо на основе украденных словарей. Это базовый метод взлома аккаунтов.
А в описываемом мной случае злоумышленники действовали немного иначе. Во-первых, они использовали большой, распределённый по разным странам ботнет из нескольких сотен заражённых компьютеров. В системе мониторинга всё выглядело так, словно это были совершенно разные компьютеры, либо прокси-серверы, за которыми сидели реальные люди и обращались к сайту. Такая атака долго может оставаться незамеченной.
Второй особенностью атаки, помимо сильной географической распределённости, был перебор не паролей, а логинов. Вероятно, злоумышленники использовали словари популярных паролей и украденные списки логинов. И сначала к известному паролю брался один логин, затем другой, третий и так далее. Было очень похоже на ситуацию, когда обычные пользователи, подключённые через одного провайдера, никак не могут залогиниться со своими паролями. То есть на первый взгляд ничего криминального. К тому же обращения к ресурсу были очень редкими – одно-два в минуту.
Третья особенность атаки была в том, что у ботнета было очень «человеческое» поведение: клиенты обрабатывали JavaScript, принимали куки.
Из-за этого комплекса факторов атака довольно долго оставалась незамеченной. Когда мы её все же обнаружили, то задались нетривиальным вопросом: как защищаться? У всех компьютеров ботнета не было каких-то особых отличительных признаков, за исключением определённой ошибки в user agent’е. Но мы не стали блокировать атаку на основе этого признака, потому что в таком случае перестали бы видеть действия злоумышленника. Нужно было выделить какие-то другие аномалии. С точки зрения IP-адресов ничего особенного не происходило. Блокировать логины, которые совершают большое количество неуспешных попыток входа, тоже нельзя, потому что частота очень низкая, и перебирается не пароль, а логин. Оставался один-единственный способ — внедрять капчу. Но заказчик очень не хотел этого делать, поскольку считал, что капча может оттолкнуть многих клиентов. А тем временем злоумышленникам уже удалось подобрать правильные комбинации к некоторым учётным записям.
Наверняка вы недоумеваете: зачем кому-то взламывать аккаунты клиентов интернет-магазина? Дело в том, что в личном кабинете накапливаются бонусные баллы, которые можно использовать для получения скидки на товары. Вероятно, кому-то очень хотелось закупиться или продать бонусные баллы в интернете.
В итоге мы уговорили клиента внедрить капчу средствами F5: она должна была появляться после заданного числа неуспешных входов. Но для начала нужно было настроить в системе критерии успешности входа. Это оказалось чуть сложнее, чем выглядело, потому что в некоторых случаях ресурс даёт одинаковый код ответа на любые попытки входа. В качестве критерия успешности входа мы выбрали передачу клиенту доменного куки.
В последней версии F5 ASM появилась возможность реагировать на попытки подбора с точки зрения Device ID — уникального идентификатора браузера. В страницу добавляется JS-код, и когда зараженная машина открывает эту страницу, то сообщает свой уникальный идентификатор. В случае с нашими злоумышленниками получилось так, что Device ID браузера был одним и тем же для каждого IP-адреса. То есть фактически с одного IP-адреса обращался один браузер.
Поэтому можно задать следующий критерий: если с одного браузера в течение 15 минут совершается больше 5 неуспешных попыток входа, то этому клиенту показывается капча. Если это действительно нормальный пользователь, он её решит и спокойно залогинится. На случай, если браузер не поддерживает JavaScript, мы добавили исключения. Но, чтобы не ослабить защиту, использовали другой критерий: если с одного IP-адреса делается больше 20 неуспешных попыток входа, опять предлагается капча. Опять же: для нормального пользователя это не создаст проблем.
Но сегодня уже есть методы обхода защиты с помощью капчи. Например, ботнеты пересылают капчи на «аутсорсинг» — в Китай или Индию, где трудолюбивые местные жители за небольшое вознаграждение решают капчи и возвращают текстовые значения. Но и в этом случае можно предпринять соответствующие меры: даже если при решённых капчах попытки входа неуспешны, можно блокировать запросы с определенного IP или Device ID при превышении заданного числа неуспешных попыток.
Последний раз, когда интернет-магазин атаковали таким образом, мы обошлись капчей, и это сработало. После ее внедрения brute-force атака постепенно стала затухать и в конце концов прекратилась. С тех пор прошло около года — рецидивов не было.
Андрей Черных, эксперт Центра информационной безопасности «Инфосистемы Джет»
Комментарии (29)
sebres
19.06.2018 12:08Но мы не стали блокировать атаку на основе этого признака, потому что в таком случае перестали бы видеть действия злоумышленника.
В хонепот его, гада...
и когда зараженная машина открывает эту страницу, то сообщает свой уникальный идентификатор.
То пока они не нашли что он у вас проверяется, т.к. и InBrowserlD и Device-ID можно довольно быстро менять...
Пока же кроме IP (ну и возможно еще длинного и долгоиграющего DH-сессионного ключа https-сессии) еще ничего не придумали.
JetHabr Автор
19.06.2018 13:54То пока они не нашли что он у вас проверяется, т.к. и InBrowserlD и Device-ID можно довольно быстро менять...
Поскольку индентификатор браузера генерирует F5, атакующим пришлось бы подстраиваться под методы генерации, что уже существенно усложнило бы атаку.
Пока же кроме IP (ну и возможно еще длинного и долгоиграющего DH-сессионного ключа https-сессии) еще ничего не придумали.
У коллег похожая атака производилась с адресов, которые были в известных репутационных списках, для них бы метод блокировки по IP, безусловно, сработал. В нашем случае адреса не фигурировали ни в одном из известных списков, и при блокировке по IP был риск блокировки легитимных клиентов, на что безопасность и бизнес заказчика не были готовы пойти.
Что касается DH-сессионного ключа https-сессии, в нашем случае при каждой попытке логина устанавливалась новая сессия.sebres
19.06.2018 17:23Поскольку индентификатор браузера генерирует F5, атакующим пришлось бы подстраиваться под методы генерации...
Поскольку индентификатор браузера генерирует F5… в браузере! Подстраиватся?
Скорее вероятно просто (пока) не нашли, что вы его используете...
при каждой попытке логина устанавливалась новая сессия
Думается мне вы путаете DH-сессию с какой-то другой. Длительность DH-сессии задаётся в обработчике https-слоя и в нормальном виде не зависит от логина и т.п…
DH-ключи (особенно для длинных сертификатов) не обновляются на протяжении длительных интервалов времени.
ISVLabs
19.06.2018 13:01или я в этом мало понимаю, но неужели сложно отфильтровать куки в клиенте? да и каждый раз генерить или брать из списка client id, чтобы он не повторялся. так что, сработавший способ это не ваша заслуга, а недоработка и лень хакеров :)
JetHabr Автор
19.06.2018 14:06Не очень понятно, что имелось в виду под «отфильтровать куки в клиенте».
Что касается генерации client id — идентификатор клиента генерировал F5.ISVLabs
19.06.2018 14:13Не очень понятно, что имелось в виду под «отфильтровать куки в клиенте».
не сохранять те, которые могут в будущем скомпрометировать как повторного посетителя. или сохранять все, но только в пределах одного сеанса.JetHabr Автор
19.06.2018 14:31Так и было. Каждый раз при попытке входа генерировался новый набор кук/сессионных ключей и т.д.
StallinHrusch
19.06.2018 18:31+1Что касается генерации client id — идентификатор клиента генерировал F5
там уже выше написали, но я повторю. Этот айди сгенерирован на клиенте, хранится на клиенте и полностью подконтролен клиенту. Достать\найти его там — вопрос времени\лени. Основывать хоть какую-либо защиту на клиенте — это все равно что прикрыться зонтиком во время цунамиJetHabr Автор
19.06.2018 18:32Описанный случай, естественно, не универсальный. Я описал защиту в условиях имеющихся ограничений (невозможность доработки веб-приложения, ограниченность во времени). На ID клиента, конечно, можно влиять, но такой способ в любом случае усложняет атаку. А дальше, да — вопрос времени/лени атакующего, но время это было бы для нас очень кстати.
HaZeR
19.06.2018 16:36+1Альтернативный извращенный костыль. Срисовывать атакующие ip и при попытке залогинится с них, пускать только при повторном вводе пароля, а первый раз всегда выдавать ошибку с записью в куки или сессию. Юзер подумает что ошибся при наборе и повторит ввод(проверяем наличия предыдущего кривого ввода — пускаем), а бот отвалится.
JetHabr Автор
19.06.2018 16:37+1Для крупного энтерпрайза такой костыль не подойдет. Бизнес ни за что на такое не пойдет. С точки зрения юзабилити для клиентов это еще хуже, чем капча.
И если к капче все уже более-менее привыкли, то как клиенты отреагируют на такое поведение сайта — не понятно.HaZeR
19.06.2018 17:04Это только для атакующих ip, поэтому проблем не будет. Юзеры с нормальных ip как обычно заходят с первого раза.
Можно было еще доп. куки на клик или движение мыши повесить. Если бот эмулирует не полностью, тоже прокатит.
не воспринимайте слишком серьезно, просто возможные решения без капчи.
Karpion
19.06.2018 17:53Ну, я бы предложил примерно такой алгоритм противодействия:
При входе с неправильным логином, если такого логина нет в базе — имитируем удачный вход. Пусть атакующие пытаются воспользоваться таким логином — и тратят на это свои силы. Заодно можно будет узнать, на какой адрес атакующие закажут доставку товара.
При входе с правильным логином и неверным паролем — тоже имитировать удачный вход, но в виде картинки сообщать, что вход неудачный. Короче говоря — морочить атакующему голову, как отличить удачную попытку входа от неудачной.
Дальше можно рандомно менять имена полей ввода. Как правило, атакующие один раз настраивают атакующий скрипт на отправку запроса, считая, что поле для имени = login, поле для пароля = password.
Как тут уже предложили — через JS отслеживать поведение пользователя — нажатие клавиш и движение мыши. Вряд ли атакующий скрипт будет полноценно имитировать поведение пользователя.
Идеально было бы настроить вход не по паролю (который реально подобрать), а по ключу, как в SSh. Вот только не знаю, насколько это годится для простых юзеров; обычно это делают крутые сисадмины для себя или для натасканных юзеров.
Ещё есть вариант — привязка логина к IP-адресу или к IP-сети класса C (или что там выдаёт провайдер). Однозначная привязка не обязательна — но добавление IP-адреса в список привязанных к логину проводить по сложной процедуре типа дополнительной авторизации через SMS.JetHabr Автор
19.06.2018 18:30Первый вариант любопытный с точки зрения запутывания атакующего, но требует значительных изменений приложения, а у нас с этим, как я уже писал, была проблема.
Про вход по ключам — это все-таки не банковская система, пострадает юзабилити + потребуются существенные затраты.
Про привязку логина к IP — тоже уже пахнет банковским антифродом, слишком затратно для данной задачи.
YourChief
19.06.2018 19:13Мне кажется, лучшим решением было бы:
- Внедрить парольную политику, требующую надежных паролей.
- Посмотреть примерный список паролей, которые пытаются использовать брутфорсеры.
- Найти в базе пользователей, которые используют эти пароли. Это может быть затратно по вычислениям, но это разовая операция.
- Принудительно сменить пользователям пароли и разослать их на почту.
То, что было реализовано, больше похоже на «любые костыли за ваши деньги» — решение чрезмерное и слабое в долгосрочной перспективе.JekaMas
19.06.2018 20:01+1На шаге, что такое "надежный" пароль и как определенные политики "надежных" паролей ломают UX и прибыль, бизнес справедливо возмутится таким решением.
JetHabr Автор
20.06.2018 10:19Изменение парольной политики — шаг потенциально правильный, но опять же страдает удобство пользователей. Плюс сразу после принудительной смены пароля большое количество клиентов захочет сменить его обратно на «попроще», пусть он и будет удовлетворять парольной политике, но вполне вероятно попадет в ещё какой-нибудь известный словарь. Дальнейшее ужесточение парольной политики приведет к оттоку клиетов и скажется на бизнесе.
С учетом того, что мы всего лишь донастроили модуль antibruteforce в уже имеющемся WAFe F5 ASM решение получилось довольно быстрым и недорогим.YourChief
20.06.2018 13:17в уже имеющемся WAFe F5 ASM решение получилось довольно быстрым и недорогим
Как Вы можете быть уверены, что Вы решили проблему?JetHabr Автор
20.06.2018 15:01После того, как мы обнаружили атаку, следить за ней было уже не так сложно. Атакующая машина повторяла определенный набор действий.
После применения защитных мер мы по логам веб-сервера отметили, что, во-первых, выводы бонусных баллов из личного кабинета существенно сократились, а во-вторых, количество атакующих машин стало снижаться, пока не сошло на нет. Видимо, атакующий понял, что дальнейшие затраты в развитие атаки не окупят результаты.
Как я уже говорил, данный способ не универсальный, но по соотношению «затраченные ресурсы — эффективность» способ оказался вполне жизнеспособным.
Идеального способа сделать так, чтобы предотвратить любую Brute-Force атаку нет, особенно с учетом все большего их очеловечивания.
itconsulting
20.06.2018 18:17А вот, кстати, может быть аудитория подскажет — существует ли такой ресурс, на который можно залить список IP, на которых, по моему мнению, работает ботнет, в смысле — компьютеры заражены, а их владельцы, возможно, об этом не подозревают?
ArsenAbakarov
Это все никак не контрится, тут видимо у кого-то был готовый продукт и его просто не стали дорабатывать, либо посчитали что доработка «себе дороже».
Вы либо защищаете каждый чих каптчами с потерей аудитории etc.., либо сохраняете аудиторию, но подвергаетесь рискам парса, атакам через формы etc…
В вашем случае я бы просто ввел какую нибудь ненавязчивую политику паролей, даже можно просто рекомендацию с пояснением зачем это нужно (типа могут взломать и воспользоваться бонусами, ну вы поняли)
JetHabr Автор
В нашем случае заказчик не мог (не хотел) что-то менять в приложении в обозримом будущем. Поэтому пришлось организовывать капчу средствами F5.
Риск потери клиентов, конечно, был, но по итогу величина оказалась приемлемой для бизнеса (точную цифру не подскажу, это уже заказчик сам посчитал).
ArsenAbakarov
Я имел ввиду ПО со стороны лиц, осуществляющих атаку. Под все ухищрения и защиты можно подстроиться
x67
2FA, Oauth от сильных мира сего