WordPress из коробки достаточно безопасен, но стандартная конфигурация оставляет несколько уязвимых точек, которые атакуют боты и скрипт-кидди. Закрыть их можно без плагинов — правками в .htaccess, wp-config.php и functions.php. Рассмотрим основные меры защиты, которые блокируют 90% типовых атак.
Защита wp-login.php от брутфорса
Страница авторизации WordPress — главная цель ботов. Тысячи запросов в минуту к wp-login.php не только угрожают безопасности, но и нагружают сервер. Самый эффективный способ защиты — ограничение доступа по IP или добавление серверной HTTP-авторизации.
# .htaccess — ограничение доступа к wp-login.php по IP
<Files wp-login.php>
Order Deny,Allow
Deny from all
Allow from 123.45.67.89
Allow from 98.76.54.0/24
</Files>
# Альтернатива — HTTP Basic Auth поверх wp-login.php
<Files wp-login.php>
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /home/user/.htpasswd
Require valid-user
</Files>
Если IP динамический, HTTP Basic Auth — лучший выбор. Файл .htpasswd создаётся командой htpasswd -c /home/user/.htpasswd admin. Располагайте его выше document root, чтобы он не был доступен через веб.
Дополнительно можно ограничить количество попыток входа через PHP, добавив в functions.php счётчик неудачных попыток:
<?php
// functions.php — блокировка после 5 неудачных попыток входа
add_filter( 'authenticate', function( $user, $username, $password ) {
if ( empty( $username ) ) {
return $user;
}
$ip = $_SERVER['REMOTE_ADDR'];
$transient_key = 'login_attempts_' . md5( $ip );
$attempts = get_transient( $transient_key );
if ( $attempts && $attempts >= 5 ) {
return new WP_Error(
'too_many_attempts',
'Слишком много попыток входа. Попробуйте через 15 минут.'
);
}
return $user;
}, 30, 3 );
add_action( 'wp_login_failed', function( $username ) {
$ip = $_SERVER['REMOTE_ADDR'];
$transient_key = 'login_attempts_' . md5( $ip );
$attempts = get_transient( $transient_key );
set_transient( $transient_key, ( $attempts ? $attempts + 1 : 1 ), 15 * MINUTE_IN_SECONDS );
});
// Сброс счётчика при успешном входе
add_action( 'wp_login', function() {
$ip = $_SERVER['REMOTE_ADDR'];
delete_transient( 'login_attempts_' . md5( $ip ) );
});
Отключение XML-RPC
Протокол XML-RPC (xmlrpc.php) использовался для удалённой публикации через Blogger-клиенты и мобильное приложение WordPress. Сегодня его заменяет REST API, а XML-RPC остаётся вектором атак — через метод system.multicall боты могут перебирать пароли, отправляя сотни комбинаций в одном HTTP-запросе.
# .htaccess — полная блокировка xmlrpc.php
<Files xmlrpc.php>
Order Deny,Allow
Deny from all
</Files>
Если на сервере используется Nginx, добавьте в конфиг:
# nginx — блокировка xmlrpc.php
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
return 444;
}
Дополнительно отключите XML-RPC на уровне WordPress, чтобы он не обрабатывал запросы даже если файл доступен:
<?php
// functions.php — отключение XML-RPC
add_filter( 'xmlrpc_enabled', '__return_false' );
// Убираем заголовок X-Pingback из HTTP-ответов
add_filter( 'wp_headers', function( $headers ) {
unset( $headers['X-Pingback'] );
return $headers;
});
// Убираем ссылку на xmlrpc из <head>
remove_action( 'wp_head', 'rsd_link' );
Права на файлы и каталоги
Неправильные права доступа — частая причина взломов на shared-хостингах. WordPress рекомендует следующие права:
- Каталоги:
755(rwxr-xr-x) — владелец может всё, остальные только читать и переходить - Файлы:
644(rw-r–r–) — владелец читает и пишет, остальные только читают - wp-config.php:
440или400— только чтение для владельца и группы - .htaccess:
444— только чтение (после настройки)
Установить права массово можно командами:
# Права на каталоги
find /path/to/wordpress -type d -exec chmod 755 {} \;
# Права на файлы
find /path/to/wordpress -type f -exec chmod 644 {} \;
# Особые права для wp-config.php
chmod 440 /path/to/wordpress/wp-config.php
Заголовки безопасности в .htaccess
HTTP-заголовки безопасности защищают от XSS-атак, clickjacking и MIME-sniffing. Добавьте их в .htaccess:
# .htaccess — заголовки безопасности
<IfModule mod_headers.c>
# Защита от clickjacking
Header always set X-Frame-Options "SAMEORIGIN"
# Защита от MIME-sniffing
Header always set X-Content-Type-Options "nosniff"
# XSS-фильтр браузера
Header always set X-XSS-Protection "1; mode=block"
# Referrer Policy — не передавать URL при переходе на HTTP
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Запрет встраивания в iframe на чужих сайтах
Header always set Content-Security-Policy "frame-ancestors 'self'"
# Permissions Policy — отключаем камеру, микрофон, геолокацию
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
Проверить наличие заголовков можно через curl -I https://yourdomain.com или сервис securityheaders.com.
Отключение редактора файлов в админке
WordPress позволяет редактировать файлы тем и плагинов прямо из админки (Внешний вид → Редактор). Если злоумышленник получит доступ к административной учётной записи, он сможет внедрить бэкдор через встроенный редактор. Отключите его одной строкой в wp-config.php:
// wp-config.php — отключение редактора файлов
define( 'DISALLOW_FILE_EDIT', true );
// Ещё жёстче — запрет установки и обновления плагинов/тем через админку
define( 'DISALLOW_FILE_MODS', true );
Константа DISALLOW_FILE_MODS также отключает автоматические обновления. Используйте её только если обновляете WordPress через WP-CLI, Git или CI/CD.
Смена префикса таблиц БД
Стандартный префикс wp_ облегчает SQL-инъекции — атакующий заранее знает имена таблиц. Менять префикс лучше при установке WordPress, но можно и на работающем сайте. Сначала измените значение в wp-config.php:
// wp-config.php — кастомный префикс
$table_prefix = 'krc_';
Затем переименуйте все таблицы в базе данных через SQL:
-- Переименование основных таблиц (MySQL)
RENAME TABLE wp_posts TO krc_posts;
RENAME TABLE wp_postmeta TO krc_postmeta;
RENAME TABLE wp_options TO krc_options;
RENAME TABLE wp_users TO krc_users;
RENAME TABLE wp_usermeta TO krc_usermeta;
RENAME TABLE wp_terms TO krc_terms;
RENAME TABLE wp_termmeta TO krc_termmeta;
RENAME TABLE wp_term_taxonomy TO krc_term_taxonomy;
RENAME TABLE wp_term_relationships TO krc_term_relationships;
RENAME TABLE wp_comments TO krc_comments;
RENAME TABLE wp_commentmeta TO krc_commentmeta;
RENAME TABLE wp_links TO krc_links;
-- Обновление мета-ключей, которые содержат префикс
UPDATE krc_options SET option_name = REPLACE(option_name, 'wp_', 'krc_')
WHERE option_name LIKE 'wp_%';
UPDATE krc_usermeta SET meta_key = REPLACE(meta_key, 'wp_', 'krc_')
WHERE meta_key LIKE 'wp_%';
Обязательно сделайте бэкап базы данных перед этой операцией. После смены префикса проверьте работу сайта, админки и плагинов — некоторые плагины хранят имена таблиц в своих настройках.
Дополнительные меры
Несколько быстрых правок, которые закрывают оставшиеся дыры:
- Скройте версию WordPress — удалите мета-тег generator:
remove_action('wp_head', 'wp_generator'); - Запретите листинг каталогов: добавьте
Options -Indexesв .htaccess - Отключите вывод ошибок PHP на продакшне:
define('WP_DEBUG', false); - Используйте HTTPS — добавьте
define('FORCE_SSL_ADMIN', true);в wp-config.php - Ограничьте REST API для неавторизованных пользователей, если он не используется на фронтенде
- Удалите readme.html и license.txt из корня — они раскрывают версию WordPress
Все описанные меры работают на уровне WordPress и веб-сервера. Не забывайте про серверную безопасность: обновляйте PHP, настройте fail2ban для SSH и wp-login.php, используйте сложные пароли и двухфакторную аутентификацию. Безопасность — это не одноразовая настройка, а набор привычек.
