REST API в WordPress часто открывает больше, чем нужно. На живом сайте это видно по двум типовым сценариям: поисковики и боты дергают публичные эндпоинты, а в логах появляются лишние запросы; либо администратор пытается «закрыть всё», после чего ломается редактор блоков, мобильные приложения, формы и интеграции плагинов. Полное отключение REST API — грубый инструмент. В большинстве случаев безопаснее ограничить только неавторизованные запросы и оставить рабочими те маршруты, которые нужны ядру и авторизованным пользователям.
Когда REST API действительно стоит ограничивать
Не каждый сайт нуждается в жестком ограничении. Если у вас обычный корпоративный сайт, где REST API используется только редактором и несколькими плагинами, можно сузить доступ довольно агрессивно. Если же сайт отдает данные во фронтенд через JavaScript, использует headless-сценарий, мобильное приложение или внешнюю интеграцию, правила должны быть точнее.
Проблема обычно выглядит так:
- в логах много запросов к
/wp-json/от неавторизованных пользователей; - внешние сервисы получают данные, которые не должны быть публичными;
- плагин безопасности предлагает «отключить REST API», но после этого в админке начинаются ошибки;
- нужно оставить доступ к отдельным маршрутам, например для форм, поиска или собственного фронтенда.
Диагностика: что именно открыто сейчас
Перед изменениями проверьте, какие маршруты реально доступны без авторизации. Самый простой способ — открыть несколько адресов в браузере или через curl. Если сайт отвечает JSON без запроса логина, значит маршрут публичный.
curl -I https://example.com/wp-json/Для более точной проверки можно посмотреть конкретные маршруты. У стандартного WordPress часто доступны:
curl https://example.com/wp-json/wp/v2/posts?per_page=1Если ответ приходит без ошибки авторизации, это не обязательно проблема. Публичные записи и страницы WordPress действительно могут быть доступны через REST API. Вопрос в том, нужны ли вам именно эти данные наружу.
Что проверить до внедрения
- использует ли сайт Gutenberg и редактирование записей в админке;
- есть ли формы, которые отправляют данные через REST API;
- есть ли фронтенд-скрипты, которые читают
/wp-json/; - используются ли плагины, которым нужен REST API для синхронизации или авторизации;
- есть ли отдельные публичные маршруты, которые нельзя закрывать.
Рабочий способ: ограничить REST API через фильтр
Самый предсказуемый вариант — использовать фильтр rest_authentication_errors. Он срабатывает до обработки маршрута и позволяет вернуть ошибку для неавторизованных запросов. При этом можно оставить исключения для админки, авторизованных пользователей и нужных эндпоинтов.
Добавьте код в functions.php дочерней темы или в небольшой mu-plugin. Второй вариант надежнее: правило не потеряется при смене темы.
<?php
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
// Авторизованным пользователям доступ не режем.
if ( is_user_logged_in() ) {
return $result;
}
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
// Разрешаем базовые маршруты, если они нужны фронтенду.
$allowed_prefixes = array(
'/wp-json/',
);
foreach ( $allowed_prefixes as $prefix ) {
if ( strpos( $request_uri, $prefix ) !== false ) {
// Здесь можно добавить более точечные исключения по маршрутам.
break;
}
}
// Если нужен жесткий режим, возвращаем ошибку для всех неавторизованных запросов.
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
} );Этот пример намеренно жесткий. В реальном проекте его почти всегда нужно доработать: оставить доступ к конкретным маршрутам, которые использует фронтенд или плагин.
Более безопасный вариант: закрыть только часть маршрутов
Если вам не нужно рубить API целиком, лучше ограничить отдельные namespace или типы запросов. Например, можно запретить неавторизованным пользователям доступ к пользовательским данным и оставить публичные записи.
<?php
add_filter( 'rest_endpoints', function( $endpoints ) {
if ( is_user_logged_in() ) {
return $endpoints;
}
// Пример: убираем эндпоинты пользователей для гостей.
if ( isset( $endpoints['/wp/v2/users'] ) ) {
unset( $endpoints['/wp/v2/users'] );
}
if ( isset( $endpoints['/wp/v2/users/(?P<id>[\\d]+)'] ) ) {
unset( $endpoints['/wp/v2/users/(?P<id>[\\d]+)'] );
}
return $endpoints;
} );Такой подход полезен, когда задача не в «закрыть всё», а в уменьшить поверхность атаки и убрать лишнюю выдачу данных. Но он не заменяет полноценную проверку прав доступа в собственных маршрутах.
Сравнение подходов
| Подход | Что делает | Плюсы | Минусы |
|---|---|---|---|
| Плагин безопасности | Отключает или ограничивает REST API через интерфейс | Быстро внедрить, не нужен код | Может сломать нужные маршруты, меньше контроля |
Фильтр rest_authentication_errors | Блокирует неавторизованные запросы на раннем этапе | Гибко, можно точечно разрешать исключения | Нужно тестировать совместимость |
Фильтр rest_endpoints | Убирает отдельные маршруты | Подходит для частичного ограничения | Не решает все сценарии, если маршрут нужен плагину |
Пошаговое внедрение без сюрпризов
- Сделайте резервную копию файлов и базы.
- Проверьте, какие плагины и скрипты используют
/wp-json/. - Добавьте правило сначала на staging-сайт.
- Ограничьте только один проблемный маршрут, а не весь API.
- Проверьте админку, редактор блоков и публичную часть сайта.
- Посмотрите логи сервера и ошибки JavaScript в браузере.
Как проверить, что решение сработало
После внедрения важно не ограничиться открытием главной страницы. Проверка должна быть практической.
- Откройте
/wp-json/в режиме инкогнито: если доступ закрыт, вы увидите ошибку 401 или 403. - Войдите в админку и убедитесь, что редактор записей работает без ошибок.
- Проверьте формы, которые отправляют данные на сайт.
- Откройте консоль браузера и убедитесь, что нет ошибок загрузки REST-запросов.
- Посмотрите, не исчезли ли нужные маршруты у плагинов, которые завязаны на API.
Если сайт использует собственный фронтенд на JavaScript, отдельно проверьте запросы к API через вкладку Network. Иногда проблема проявляется не сразу, а только на страницах с динамической подгрузкой данных.
Частые ошибки и как их исправить
Полностью закрыли REST API и сломали редактор
Это самая частая ошибка. Gutenberg и часть плагинов используют REST API для сохранения и загрузки данных. Если после ограничения перестали сохраняться записи, значит правило слишком жесткое. Решение — вернуть доступ авторизованным пользователям и сузить только гостевые запросы.
Проверяют только главную страницу
Главная может открываться нормально, даже если в админке уже есть ошибки. Проверяйте именно редактор, формы, поиск, личный кабинет и любые страницы с динамическими запросами.
Используют $_SERVER['REQUEST_URI'] без учета исключений
Если вы сравниваете URI слишком грубо, можно случайно заблокировать нужный маршрут. Лучше сначала собрать список реально используемых эндпоинтов, а потом добавлять исключения точечно.
Вносят код в активную тему
После обновления темы ограничение может исчезнуть. Для технических правил безопасности лучше использовать mu-plugin или отдельный мини-плагин.
Безопасность и производительность: что учесть на практике
Ограничение REST API не должно становиться заменой нормальной защиты. Если у вас слабые пароли, открытая авторизация по XML-RPC или устаревшие плагины, закрытие API не решит проблему. Это только уменьшит лишнюю экспозицию.
С точки зрения производительности ограничение может немного снизить шум в логах и количество бесполезных запросов, но не стоит ждать от него чудес. Если сайт медленный, сначала проверьте кэш, тяжелые запросы к базе и сторонние скрипты. Для чистки лишнего технического мусора и дублей часто полезнее отдельный аудит, чем точечное «закрыть всё».
Если нужен более широкий набор инструментов для технической оптимизации WordPress, можно посмотреть на Clearfy Pro. Но даже в этом случае базовую логику доступа к REST API лучше понимать и проверять руками.
Когда лучше не ограничивать API кодом
Если сайт уже завязан на несколько внешних интеграций, а вы не уверены, какие маршруты нужны, не начинайте с жесткого фильтра. Сначала соберите список запросов, посмотрите логи и протестируйте на staging. В некоторых проектах безопаснее оставить REST API открытым для чтения публичных данных и закрыть только чувствительные маршруты через права доступа внутри самого плагина.
Именно в этом сценарии кодовая блокировка должна быть последним шагом, а не первым. Тогда вы не получите ситуацию, когда защита есть, а сайт перестал нормально редактироваться.