Предотвращаем брутфорс-атаки в WordPress с помощью Fail2Ban

https://www.youtube.com/watch?v=XvluDYshyEM

Fail2Ban – это простой плагин, который задает заголовок состояния 401, возвращаемый в том случае, если посетитель ввел некорректные учетные данные при запросе записи.

Код плагина умещается в несколько строк:

/*
Plugin Name: Fail2Ban filter
Version: 1.0
Description: Sets a 401 Status Code which shows in access logs for use with fail2ban
Author: Tim Nash
Author URI: https://timnash.co.uk
Code Modified from  Konstantin Kovshenin original - http://kovshenin.com/2014/fail2ban-wordpress-nginx/
*/
function fail2ban_login_failed_401() {
    status_header( 401 );
}
add_action( 'wp_login_failed', 'fail2ban_login_failed_401' );

Заголовок 401 записывается в мои логи доступа наряду с другой информацией о посетителе – это стандартный лог доступа и стандартное поведение для большинства серверов. Поскольку логи доступа представляют собой обычные текстовые файлы, они могут быть легко отслежены через разные приложения, и одно из таких приложений – это fail2ban. Некоторые пользователи спрашивали меня о том, как установить Fail2ban для работы с плагинами, поэтому я решил создать короткое видео-руководство вместе с более детальным объяснением конфигурации ниже.

Fail2Ban и конфигурация WordPress

Fail2Ban – это утилита, которую можно найти в большинстве систем Linux (если вы используете виртуальный хостинг, вы можете узнать у своего провайдера, установлена ли она, и могут ли к ней применяться дополнительные фильтры). Она отслеживает логи и работает как простой интерфейс для серии команд, включая взаимодействие с IPTables, стандартным unix файрволом. Если утилита не установлена, вы можете сделать это самостоятельно в Ubuntu:

sudo apt-get install fail2ban

После установки ее можно легко сконфигурировать. Fail2Ban отслеживает логи и фиксирует неудачные попытки входа, используя регулярные выражения. Эти регулярные выражения хранятся в разделе фильтров /etc/fail2ban/filters.d/. По умолчанию утилита поставляется с многочисленными общими фильтрами, начиная с SSH и заканчивая конфигурацией Apache/Nginx.

Типичная конфигурация фильтра выглядит следующим образом:

# fail2ban filter configuration for WordPress Logins

[Definition]

failregex = .*POST.*(wp-login\.php|xmlrpc\.php).* 401

ignoreregex =

По существу, она состоит из двух частей — failregex и ignoreregex. failregex – то, что ищет Fail2ban; рассматривается «fail» — неудачный вход в нашем случае. regex используется для парсинга вашего лога доступа. В коде выше он проверяет заголовки состояния 401 в ответах записей, которые (ответы) были получены из wp-login.php и xmlrpc.php во время входа. Проверка не связана с путем, т.е. в теории, если у вас wp-login.php находится в подпапке, и кто-либо инициирует запрос записи, выдающий 401, это тоже будет учтено. Это, конечно, маловероятно, но стоит это помнить. В таком случае мы можем применить ignoreregex, чтобы игнорировать вызовы для определенного файла.

Если вы не разместите

ignoreregex =

Fail2ban выведет предупреждение при рестарте, поэтому, даже если у вас нет ничего, что нужно проигнорировать, просто поместите эту строку и оставьте regex пустым.

Теперь, когда фильтр на месте, мы можем задать конфигурацию бана, которая находится в /etc/fail2ban.jail.conf. Это довольно большой файл, обладающий комментариями; я добавлю свои уникальные опции конфигурации в самый его конец:

# Jail for unauthorised WordPress login attempts
# If you are using APACHE or multiple access logs change as appropriate
[wordpress]

enabled = true
port = http,https
filter = wordpress-auth
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 3600
  • Enabled – необходимо включить, чтобы все пошло, как нам нужно
  • Port – задает то, какие порты надо отслеживать (можно указывать либо число, либо портовую службу). В данном случае я определил HTTP и HTTPS, хотя мы могли бы задать 80,443.
  • Filter – фильтр, созданный нами ранее – в данном случае я создал фильтр wordpress-auth.
  • Logpath – путь к логам, которые нужно отслеживать. Мы отслеживаем стандартные Nginx логи, однако это может быть также и отдельный файл доступа, логи apache2, к примеру.
  • Maxretry – сколько раз один и тот же IP должен присутствовать в regex результатах за определенный период времени, чтобы попасть в бан. По умолчанию это 3 раза за 600 секунд, однако вы можете изменить время, задав findtime.
  • bantime – на какое время будет забанен IP (в секундах).

Как только плагин будет включен и фильтры заданы, вы можете просто перезапустить fail2ban для работы с ним. Fail2ban будет отслеживать access.log на предмет наличия неудачных логинов, занося IP в бан по мере необходимости.

Запись в syslog

В репозитории WordPress имеется плагин WP fail2ban, который работает несколько иначе, чем то, что показано в видео. Вместо использования заголовков состояния и лога доступа он просто ведет запись в syslog с помощью LOG_AUTH. То есть, если по некоторым причинам ваш лог доступа будет недоступен или запись в него будет закрыта, то заметки будут все равно оставлены (предполагая, что PHP может писать в syslog). Однако это также означает, что в вашем syslog будет много ложных записей. Если вы страдаете от распределенной брут-форс атаки, то в таком случаете ваши системные логи будут заполнены очень быстро, вследствие чего остальные ошибки будет трудно обнаружить. Однако для этого также есть многочисленные решения, и люди чаще всего не прочесывают системные логи вручную, если только они не садомазохисты.

Есть также и некоторые преимущества по ведению записи в отдельный лог или даже в syslog, особенно когда у вас запущен fail2ban на многочисленных сайтах. Сведя уведомления о неудачных входах на сайт к одной локации, вы можете отслеживать все из одного места, иначе вам придется настраивать отдельные jail-конфиги для каждого сайта.

Однако если вы работаете с одним хостом или у вас имеются централизованные логи доступа, то в таком случае использование логов доступа будет простым и легким в настройке без каких-либо дополнительных помех. Для управления логом не придется полагаться на PHP. Если у вас запущено много сайтов на разных серверах, то в таком случае вы можете рассмотреть централизацию логов; в таких ситуациях вы можете использовать инструменты, как, к примеру, monolog, для ведения отдельного централизованного лога.

Почему 401, а не 403

Мой небольшой плагин, используемый в примере, был основан на плагине Константина Ковшенина – правда, с одним небольшим изменением: он выдает 401 вместо 403. Почему? Это вопрос семантики.

  • 403 – состояние Forbidden, пользователь попытался получить ресурс, к которому у него нет доступа
  • 401 – состояние Unauthorised, пользователь попытался получить ресурс, однако он не предоставил корректных учетных данных для доступа к нему

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

В этом случае:

  • Мы отдаем 401, как и раньше, если ученые данные некорректные
  • Мы отдаем 403, если учетные данные корректные, однако мы не открываем доступ к ресурсу из-за слишком большого числа IP-адресов.

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

Не только баним, но и уведомляем об этом

Fail2Ban – это очень гибкая система; наряду со своей папкой filters.d, она также имеет и папку actions.d, позволяющую нам модульно применять разные действия, диапазон которых широк: начиная с отправки писем при успешном бане и заканчивая созданием своих собственных действий (как и в случае с фильтрами).

К примеру, я обнаружил, что почтовых уведомлений стало слишком много на сайтах с высоким трафиком, и не так давно я отключил sendmail на своих серверах по умолчанию. Однако я по-прежнему хочу знать, когда IP был забанен, поэтому мы можем создать действие, которое будет выглядеть примерно следующим образом, и будет использоваться для коммуникации со Slack через incoming webhook:

# Fail2Ban configuration for Slack Notification
# Author Tim Nash
#
[Definition]

# Option: actionban
# Notes: Command executed when banning IP.
# Values: CMD

actionban = curl -X POST --data-urlencode 'payload={"channel": "#metaworld", "username": "webhookbot", "text": "Fail2Ban Reports IP  has been banned by  filter", "icon_emoji": ":ghost:"}' https://example.slack.com/services/hooks/incoming-webhook?token=yourtoken

[Init]

# Default name of the chain

Сохраняем его как slack.conf. Вы можете получить свой токен непосредственно в webhook-разделе Slack. Опять же, код напоминает наш фильтр, который мы писали ранее, однако в данном случае мы посылаем CURL запрос, который может быть заменен на shell-скрипт или что-то иное. Затем мы можем отредактировать jail.conf для добавления нашего действия:

# Jail for unauthorised WordPress login attempts
# If you are using APACHE or multiple access logs change as appropriate
[wordpress]

enabled = true
port = http,https
filter = wordpress-auth
action = slack[name=wordpress]
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 3600

Готово. Теперь, когда IP будет забанен, нам будет отправлено уведомление в Slack на наш канал metaworld , и я могу отключить почтовые уведомления в jail.conf.

Баним тех, кто уже попадался ранее

По умолчанию Fail2Ban просто временно банит IP-адреса, однако вы очень быстро столкнетесь с ботами, которые просто научатся ждать один день, и потом пробовать снова. В таких обстоятельствах вы можете заблокировать тех, кто уже попадался ранее, на постоянной основе. Я не так давно начал использовать скрипт Repeat Offender Script, который после определенного периода блокирует IP-адрес навсегда.

В итоге мы имеем простое, эффективное решение, позволяющее остановить брутфорс атаки без использования WordPress-плагинов (за исключением тех трех строк, которые были в начале). Учитывая, что брутфорс-атаки становятся все более и более значимой проблемой для владельцев WP-сайтов, очень важно помнить, что они начались задолго до появления WordPress, и у нас имеются эффективные средства для предотвращения таких атак.

Блог про WordPress
Комментарии: 2
  1. Антон Смирнов

    Спасибо за статью, все эти советы являються отличным дополнением для остальных мер защиты.

  2. Интернет дневник

    Полезная статья, но мне это не грозит.. ведь я blogspot юзаю

Добавить комментарий

Получать новые комментарии по электронной почте.