WP REST API часто оставляют открытым по умолчанию, а потом удивляются лишним запросам к /wp-json/, светящимся данным о сайте и шуму в логах. Полностью отключать API обычно плохая идея: Gutenberg, админка и часть плагинов на нём завязаны. Рабочий сценарий другой — ограничить публичные маршруты, но не сломать то, что реально используется внутри сайта.
Ниже разберём, как понять, что именно у вас торчит наружу, какие маршруты можно прикрыть, и как проверить, что после правки сайт продолжает работать нормально.
Когда проблема действительно в REST API
Сначала стоит убедиться, что речь не о ложной тревоге. Сам по себе /wp-json/ — не ошибка. Проблема начинается, когда:
- в логах много запросов к REST-маршрутам от ботов и парсеров;
- по адресу
/wp-json/wp/v2/usersили похожим endpoint’ам видны данные, которые вы не хотите отдавать публично; - внешние сервисы дергают API без авторизации и получают слишком много информации;
- после установки плагина безопасности сайт начал отдавать 403 на запросы редактора или мобильного приложения;
- нужно оставить API только для авторизованных пользователей или конкретных интеграций.
Что проверить перед изменениями
Откройте в браузере или через curl несколько адресов и посмотрите, что реально отдается:
curl -I https://example.com/wp-json/curl -s https://example.com/wp-json/wp/v2/users | headЕсли второй запрос возвращает JSON с пользователями или метаданными, это не всегда уязвимость, но это уже повод ограничить публичный доступ к части маршрутов.
Какие есть варианты: код, плагин или серверное правило
Для этой задачи обычно используют три подхода. У каждого есть компромисс.
| Подход | Что делает | Плюсы | Минусы |
|---|---|---|---|
| Код в теме или mu-plugin | Фильтрует REST-маршруты на уровне WordPress | Точечно, прозрачно, можно оставить нужные endpoint’ы | Нужно аккуратно тестировать |
| Плагин безопасности | Даёт готовые настройки и исключения | Быстро включить, меньше кода | Не всегда понятно, что именно он блокирует |
| Правило на сервере | Режет доступ до WordPress | Снижает нагрузку раньше PHP | Легко сломать редактор и интеграции |
Если нужен контроль без лишней магии, практичнее начать с кода. Для точечной задачи это обычно предсказуемее, чем глобальные настройки безопасности.
Пошаговое решение: закрываем публичные маршруты и оставляем рабочие
Самый безопасный вариант — не отключать REST API целиком, а ограничить только публичные ответы для неавторизованных пользователей. Для этого удобно использовать фильтр rest_authentication_errors.
Вариант 1: блокировать REST API для гостей
Если сайт не использует публичные API-запросы от внешних сервисов, можно запретить доступ неавторизованным пользователям. Код лучше класть в mu-plugin или в отдельный мини-плагин, а не в functions.php активной темы.
<?php
/**
* Plugin Name: Restrict REST API for guests
*/
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( is_user_logged_in() ) {
return $result;
}
// Разрешаем только базовый индекс API, если он нужен для диагностики.
$uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
if ( strpos( $uri, '/wp-json/' ) !== false ) {
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
}
return $result;
} );Это грубый вариант. Он подходит, если у вас нет публичных интеграций и вы точно понимаете, что блокируете. Для обычного сайта чаще нужен более мягкий фильтр.
Вариант 2: закрыть только чувствительные маршруты
Чаще всего достаточно запретить отдельные endpoint’ы, например список пользователей. Так вы не ломаете весь API, но убираете лишнюю утечку данных.
<?php
add_filter( 'rest_endpoints', function( $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 для редактора, блоков и плагинов.
Вариант 3: ограничить доступ только для конкретных маршрутов
Если внешняя интеграция использует один маршрут, а остальное API не нужно, можно проверять namespace и разрешать только нужное. Это уже более точечная настройка, но и ответственность выше: надо знать, какие запросы делает сайт.
<?php
add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
if ( is_user_logged_in() ) {
return $result;
}
$route = $request->get_route();
// Разрешаем только публичные служебные запросы, если они нужны.
$allowed = array(
'/wp/v2/posts',
'/wp/v2/pages',
);
foreach ( $allowed as $prefix ) {
if ( strpos( $route, $prefix ) === 0 ) {
return $result;
}
}
return new WP_Error(
'rest_forbidden',
__( 'Этот REST-маршрут закрыт для гостей.', 'textdomain' ),
array( 'status' => 403 )
);
}, 10, 3 );Этот код уже требует тестирования на конкретном сайте. Если у вас есть формы, headless-фронтенд, мобильное приложение или SEO-плагин с REST-запросами, список разрешённых маршрутов придётся расширять.
Как не сломать редактор, формы и внешние сервисы
Главная ошибка — блокировать всё подряд без проверки зависимостей. Gutenberg, некоторые блоки, автосохранение и плагины аналитики могут использовать REST API для внутренних запросов. Поэтому перед включением ограничения проверьте, что у вас есть:
- работающий вход в админку;
- открытие и сохранение записей в редакторе;
- формы, которые отправляют данные через AJAX или REST;
- внешние сервисы, если они подключены к сайту;
- мобильные приложения или headless-фронтенд, если они есть.
Если сайт корпоративный и у него много интеграций, лучше сначала ограничить только чувствительные маршруты, а не весь API. Это снижает риск случайно отрезать нужный функционал.
Проверка результата после внедрения
После правки не ограничивайтесь одной проверкой в браузере. Нужна короткая, но практичная валидация.
- Откройте
/wp-json/в браузере в режиме гостя и убедитесь, что поведение соответствует выбранной схеме. - Проверьте
/wp-json/wp/v2/users— он не должен отдавать лишние данные публично, если вы его закрывали. - Зайдите в админку и откройте редактор записи.
- Сохраните запись и проверьте, что автосохранение не сломалось.
- Если есть формы, отправьте тестовую заявку.
- Посмотрите error log и консоль браузера на предмет 401/403 и JS-ошибок.
Для быстрой проверки можно использовать curl:
curl -i https://example.com/wp-json/wp/v2/usersЕсли вы закрывали маршрут для гостей, ожидаемым результатом будет 401 или 403, а не полноценный JSON-ответ.
Частые ошибки и как их исправить
Сломали редактор после полного отключения API
Причина обычно в слишком грубом фильтре или серверном правиле, которое режет все запросы к /wp-json/. Исправление простое: верните базовый REST API и блокируйте только конкретные маршруты или неавторизованных гостей через WordPress-фильтры.
Отключили не тот endpoint
Иногда убирают маршруты, которые использует плагин SEO, формы или блоки. В этом случае сначала включите логирование запросов, потом посмотрите, какой маршрут реально нужен, и добавьте его в исключения.
Проверяли только в админке
Админка может работать, а публичная часть уже ловит ошибки. Обязательно тестируйте и фронтенд, и формы, и кэш, если он стоит на сайте.
Сделали правку в теме, а потом обновили её
Если код лежит в functions.php, он может исчезнуть после обновления. Для таких задач лучше использовать mu-plugin или отдельный мини-плагин.
Что делать, если нужен более мягкий вариант
Иногда не нужно закрывать API полностью. Достаточно убрать только публичные сведения и оставить служебные маршруты. В таком случае полезно сочетать ограничение REST API с чисткой лишних публичных endpoint’ов, отключением ненужных архивов и контролем индексации. Если у вас уже есть плагин для технической чистки сайта, например Clearfy Pro, часть подобных настроек можно собрать в одном месте, но всё равно стоит понимать, что именно он меняет.
Если задача касается не только REST API, а ещё и индексации дублей, служебных страниц и мусорных endpoint’ов, сначала составьте список того, что реально используется сайтом. Это дешевле, чем потом искать, почему редактор перестал сохранять блоки или внешняя интеграция начала получать 403.
В итоге рабочая схема выглядит так: сначала находите, какие маршруты действительно используются, потом ограничиваете только лишнее, после этого проверяете редактор, формы и публичный фронтенд. Для WordPress это почти всегда надёжнее, чем «выключить всё и посмотреть, что сломалось».