REST API в WordPress часто оставляют открытым по умолчанию, а потом удивляются лишним запросам к /wp-json/, утечке служебных данных и шуму в логах. Полностью отключать API обычно не нужно: Gutenberg, мобильные приложения и часть плагинов завязаны на него. Задача практичнее — ограничить доступ там, где он реально не нужен, и не сломать админку, редактор и публичные интеграции.
Когда проблема действительно есть
Сначала стоит понять, что именно вас беспокоит. Не каждый запрос к REST API — это атака или ошибка. Но если в логах много обращений к /wp-json/wp/v2/users, если боты массово дергают эндпоинты без пользы, если на сайте есть API-утечки через плагины или кастомные маршруты, тогда ограничение доступа оправдано.
Типичные признаки
- в access-логах много запросов к
/wp-json/от одних и тех же IP; - появляются запросы к
/wp-json/wp/v2/usersи/wp-json/wp/v2/commentsбез явной причины; - на сайте есть публичные данные, которые не должны быть доступны без авторизации;
- после установки плагина с API-эндпоинтами нагрузка выросла, а пользы от них нет;
- в админке или редакторе возникают ошибки, если кто-то уже пытался «рубить» REST API через
disable_rest_apiбез проверки.
Что именно закрывать, а что оставить
Полное отключение REST API — грубый вариант. Он может сломать блоковый редактор, предпросмотр, некоторые формы, интеграции с внешними сервисами и плагины, которые используют стандартные маршруты WordPress. Обычно безопаснее ограничить только публичные запросы к чувствительным маршрутам и оставить доступ авторизованным пользователям.
| Подход | Что делает | Риск |
|---|---|---|
| Плагин безопасности | Блокирует часть REST-запросов без кода | Может конфликтовать с другими правилами и скрывать причину проблемы |
Код в functions.php или MU-плагине | Точечно ограничивает нужные маршруты | Нужно аккуратно тестировать после обновлений |
| Полное отключение API | Ломает доступ ко всем маршрутам для гостей | Высокий риск поломки редактора и плагинов |
Диагностика: какие маршруты реально используются
Перед изменениями посмотрите, какие REST-эндпоинты дергаются на вашем сайте. Если у вас есть доступ к логам веб-сервера, это самый надежный способ. В WordPress можно также временно включить логирование на уровне плагина или отладочного файла, но не оставляйте WP_DEBUG включенным на боевом сайте надолго.
Что проверить вручную
- откройте
https://example.com/wp-json/и посмотрите, какие маршруты доступны; - проверьте, не используются ли кастомные эндпоинты плагинов;
- зайдите в редактор записей и убедитесь, что он работает без ошибок;
- посмотрите, не завязаны ли на REST формы, поиск, фильтры или фронтенд-виджеты.
Если вы не уверены, лучше начать с мягкого ограничения: закрыть только чувствительные маршруты для гостей, а не весь API целиком.
Пошаговое решение через код
Самый предсказуемый способ — добавить фильтр rest_authentication_errors и запретить доступ к выбранным маршрутам для неавторизованных пользователей. Такой подход не ломает весь API и позволяет оставить рабочими те части, которые нужны редактору и плагинам.
<?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'] ) : '';
// Закрываем только чувствительные маршруты.
$blocked_routes = array(
'/wp-json/wp/v2/users',
'/wp-json/wp/v2/comments',
);
foreach ( $blocked_routes as $route ) {
if ( strpos( $request_uri, $route ) !== false ) {
return new WP_Error(
'rest_forbidden',
__( 'REST API restricted for this route.', 'textdomain' ),
array( 'status' => 403 )
);
}
}
return $result;
} );Этот вариант простой, но есть нюанс: он опирается на REQUEST_URI. Для точечной защиты этого достаточно, если вы понимаете, какие URL хотите закрыть. Если нужен более строгий контроль, лучше проверять маршрут через сам объект запроса.
Более аккуратный вариант — использовать rest_pre_dispatch и смотреть на маршрут запроса. Так вы не зависите от структуры URI и можете точнее обрабатывать конкретные эндпоинты.
<?php
add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
if ( is_user_logged_in() ) {
return $result;
}
$route = $request->get_route();
$blocked_routes = array(
'/wp/v2/users',
'/wp/v2/comments',
);
foreach ( $blocked_routes as $blocked_route ) {
if ( strpos( $route, $blocked_route ) === 0 ) {
return new WP_Error(
'rest_forbidden',
__( 'Access denied.', 'textdomain' ),
array( 'status' => 403 )
);
}
}
return $result;
}, 10, 3 );Если нужно закрыть REST API полностью для гостей
Иногда задача именно такая: сайт не использует публичные REST-запросы, а редактор и админка работают только для авторизованных пользователей. Тогда можно отключить API для неавторизованных посетителей, но делать это нужно осторожно и после теста на staging.
<?php
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( is_user_logged_in() ) {
return $result;
}
return new WP_Error(
'rest_not_allowed',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
} );Такой код лучше размещать в MU-плагине, а не в functions.php активной темы. Тогда защита не исчезнет при смене темы.
Когда этот вариант не подходит
- если сайт использует фронтенд-редактор или headless-сценарий;
- если формы, поиск или фильтры обращаются к REST API;
- если у вас есть мобильное приложение или внешняя интеграция;
- если редакторы жалуются на ошибки при сохранении блоков.
Проверка результата после внедрения
После изменения правил не ограничивайтесь открытием главной страницы. Проверьте несколько сценариев отдельно: публичный доступ, редактор, авторизованный доступ и проблемные маршруты.
- откройте
/wp-json/в браузере без авторизации; - проверьте
/wp-json/wp/v2/usersи убедитесь, что доступ закрыт; - войдите в админку и откройте редактор записи;
- сохраните запись и проверьте, нет ли ошибок в консоли браузера;
- посмотрите access-лог: нужные маршруты должны отдавать
403или401, а не200.
Если у вас есть мониторинг, полезно отдельно проверить, не выросло ли число ошибок rest_forbidden после внедрения. Это покажет, не задели ли вы легитимные запросы.
Частые ошибки и как их исправить
Отключили REST API целиком и сломали редактор
Такое часто происходит, когда используют слишком агрессивный код или плагин, который блокирует все маршруты без исключений. Решение — убрать глобальный запрет и перейти к списку конкретных маршрутов.
Проверяют только URL, а не маршрут
Если фильтрация завязана на строку в REQUEST_URI, можно промахнуться мимо варианта с параметрами, прокси или нестандартной структурой URL. Для точности лучше использовать $request->get_route().
Размещают код в теме
При смене темы защита исчезает. Для системных ограничений лучше использовать MU-плагин или небольшой собственный плагин.
Блокируют API, но не проверяют плагины
Некоторые плагины используют REST API для фронтенда, статистики, форм или интеграций. После изменений нужно пройтись по ключевым пользовательским сценариям, а не только по главной странице.
Практические советы по безопасности и производительности
Если цель — не просто закрыть API, а уменьшить поверхность атаки, не ограничивайтесь одним фильтром. Посмотрите на сопутствующие вещи: отключите лишние публичные маршруты в плагинах, уберите ненужные XML-RPC-интеграции, проверьте права пользователей и не храните секреты в открытых endpoint-ах.
- не отключайте REST API без теста на копии сайта;
- не закрывайте все маршруты, если сайт использует Gutenberg;
- не ставьте несколько плагинов безопасности, которые дублируют одни и те же ограничения;
- после обновления WordPress и плагинов повторно проверьте маршруты;
- если нужен быстрый способ убрать дубли и лишние служебные элементы, посмотрите на Clearfy Pro, но все равно тестируйте совместимость с вашим стеком.
Для сайтов, где REST API используется только частично, такой точечный подход обычно надежнее, чем попытка «выключить всё и забыть». Он оставляет рабочими нужные сценарии и дает понятный контроль над тем, что именно доступно извне.