ГлавнаяРазноеНастройка fail2ban для защиты WordPress

Настройка fail2ban для защиты WordPress

Мы уже рассматривали плагин Limit Login Attempts, который защищает WordPress от перебора паролей. В этой статье мы рассмотрим альтернативный подход на системном уровне с помощью популярной программы fail2ban.

Обратите внимание, что данная статья нацелена на пользователей VPS хостинга и владельцев выделенных серверов. Для установки и настройки fail2ban вам потребуется root-доступ к вашему хостинг-аккаунту и базовые навыки системного администрирования.

Fail2ban

Fail2ban — это системная утилита, которая сканирует логи на определенные записи, и имеет возможность выполнять ряд действий при их обнаружении. Самый простой пример это сканирования журнала доступа по SSH к вашему серверу, и при обнаружении 5 неудачных попыток, заблокировать доступ по IP адресу.

Установить fail2ban на большинстве Linux-систем можно с помощью менеджера пакетов aptitude, apt-get, yum и т.д. На нашем тестовом сервере Ubuntu мы сделали это следующим образом:

$ sudo apt-get install fail2ban

После установки утилиты, вы найдете все ее конфигурационные файлы в директории /etc/fail2ban, включая директорию action.d для действий, и директорию filter.d для фильтров.

Фильтр в fail2ban это набор правил, по которым утилита будет искать определенные вхождения в лог-файлах. Примеры фильтров: попытка входа по SSH, попытка авторизации в Apache, попытка входа через FTP.

Действия в fail2ban запускаются тогда, когда фильтр сработал определенное количество раз. Действия тоже могут быть разными, например: блокировка IP адреса с помощью iptables, отправка оповещения на электронную почту администратору.

Основной файл который собирает все правила вместе в fail2ban называется jail.conf (тюрьма). Там прописываются фильтры и действия, максимальное количество попыток, время блокировки и многое другое. К этому файлу мы скоро вернемся.

WordPress и Fail2ban

Для того, чтобы fail2ban мог понять, что произошла неудачная попытка авторизации в WordPress, нам необходимо об этом явно сообщить со стороны самого WordPress. Сделать мы это можем с помощью простого плагина:

/**
 * Plugin Name: Return 403 on Failed Login
 */
function my_login_failed_403() {
    status_header( 403 );
}
add_action( 'wp_login_failed', 'my_login_failed_403' );

По умолчанию WordPress использует HTTP код 200, даже при неудачных попытках авторизации, поэтому глядя на журнал доступа веб-сервера Apache или nginx, сложно сказать была ли попытка успешной. С помощью нашего простого плагина, мы используем код 403 для указания неуспешных попыток входа в WordPress.

После активации плагина убедитесь в том, что он действительно работает. Сделать это можно посмотрев на логи доступа вашего веб-сервера, например в /var/log/nginx/access.log для nginx, или /var/log/apache2/access.log для веб-сервера Apache.

Фильтр fail2ban для WordPress

Создайте новый фильтр в fail2ban (в директории filter.d) и назовите его wordpress-auth.conf. Данный фильтр будет выполнять поиск на 403 статус при доступе к файлам wp-login.php и xmlrpc.php в WordPress. Текст фильтра будет выглядеть следующим образом:

[Definition]
failregex = <HOST>.*POST.*(wp-login\.php|xmlrpc\.php).* 403

Данные регулярное выражение подойдет для лог-файлов Apache и nginx по умолчанию. Если вы изменили формат журнала вашего веб-сервера, вам придется изменить и регулярное выражение.

Настройка jail.conf

Новый фильтр wordpress-auth.conf легко использовать в файле конфигурации jail.conf. Добавьте следующий код в конец файла:

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

Здесь мы указываем путь к лог-файлу нашего веб-сервера, максимальное количество количество неудачных попыток авторизации, и время на которые IP адрес будет заблокирован (действие по умолчанию).

После внесения изменений в конфигурацию, перезапустите сервис fail2ban и смотрите его в действии в /var/log/fail2ban.log:

$ sudo service fail2ban restart
$ sudo tail -f /var/log/fail2ban.log

2014-01-22 16:10:44,818 fail2ban.actions: WARNING [wordpress] Ban 115.230.126.74
2014-01-22 17:29:16,103 fail2ban.actions: WARNING [wordpress] Ban 185.24.218.83
2014-01-22 18:53:02,819 fail2ban.actions: WARNING [wordpress] Ban 222.186.62.71
...

Если вы решили протестировать fail2ban на себе, не забудьте установить низкое значение параметра bantime, например 60 для блокировки доступа на одну минуту.

Учтите, что поскольку утилита fail2ban осуществляет поиск и блокировку по IP адресу, она не поможет в случае направленной атаки с большого количества разных IP-адресов. В таком случае вам необходимы другие меры защиты, например двойная аутентификация с помощью Google Authenticator. Подробности в нашей статье.

Наконец, стоит отметить, что после установки fail2ban вам уже доступны разные фильтры для отслеживания доступа по SSH, FTP и т.д. Их легко включить и настроить в файле jail.conf.

Подписаться на рассылку

Подписаться → Подпишитесь на бесплатную рассылку журнала WP Magazine и получайте новости, события, подборки тем и плагинов, уроки, советы и многое другое в мире WordPress!

  • donchenko

    Отличное решение, и раньше все срабатывало, однако сегодня обнаружил вот такую строчку:

    «POST http://****************/wp-login.php/ HTTP/1.1″ 302 198 «-» «Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.2) Gecko/2008091620 Firefox/3.0.2»

    И она не попадает под действие этого фильтра, плагин не отдает серверу 403 ошибку :( соотв ничего и не банится, понятно что можно в fail2ban прописать еще одно правило :) просто для информации решил написать.

    • Спасибо за информацию! С wp-login.php/ у вас проходит редирект на wp-login.php (без слэша) потому и 302 код, при этом WordPress даже не читает POST данные с логином и паролем, поэтому «атака» на подобный URL равносильна атаке на любую другую страницу, которая не является точкой входа в админку. Я бы на вашем месте не волновался :)

  • Unknown

    Здравствуйте, подскажите куда нужно добавить плагин:

    /**
    * Plugin Name: Return 403 on Failed Login
    */
    function my_login_failed_403() {
    status_header( 403 );
    }
    add_action( ‘wp_login_failed’, ‘my_login_failed_403’ );

    Спасибо.

    • В файл в директории wp-content/plugins или wp-content/mu-plugins. В случае с первой директорией вам небоходимо будет активировать плагин в панели администрирования WordPress.

      • Unknown

        Спасибо. Но после добавления плагина и его активации, вверху страниц выводится его содержимое. Я что-то сделал не так?

        • Да, вы наверняка забыли открывающий тег <?php в начале документа.

          • Unknown

            Еще раз спасибо! Мне так стыдно, так стыдно…

      • Серж

        Вот этот самый вопрос с самим плагином непонятен вообще. Я админю linux, но я далёк от web-разработки, а в статье этот вопрос описан очень поверхностно. Совершенно непонятно. Что куда как и зачем.

  • Slava UA

    И при апргрейде fail2ban вполне могут затереться правила, потому что неправильно пройдет merge файла конфига. Поэтому лучше использовать jail.local.

  • the_pled

    Мне кажется, вместо выдачи ошибки 403 лучше записывать неудачный вход в /var/log/nginx/error.log:

    function log_wp_login_fail($username) {
    error_log(«WP LOGIN FAILED for username: $username»);
    }
    add_action(‘wp_login_failed’, ‘log_wp_login_fail’);

    Таким образом не нарушится работа плагинов входа через AJAX, да и читать неудачные входы легче в error.log чем в огромном access.log (который, кстати, у многих выключен).

    Фильтр для fail2ban в таком случае будет:

    [Definition]
    failregex = ^.*WP LOGIN FAILED.*client: .*$

    • Хорошая идея, правда мы чуть дальше пошли и стали писать в security.log :)

      • Серж

        Можно подробнее как это сделать?

        • Я думаю, что примерно так:

          error_log(‘Сообщение об ошибке’, 3, ‘/var/log/security.log’);
          Правда я не знаю, хорошо ли вот так напрямую указывать путь до файла прямо в PHP-коде. Это можно сделать через php.ini, но, как я понял, там можно указать лишь путь до error.log, а вот такие произвольные логи — нет.

        • Хм. Похоже в Apache есть CustomLog правда я не сумел с первой попытки им воспользоваться.

  • Серж

    Не работает ((( Что я делаю не так?