REST API в WordPress часто оставляют открытым по умолчанию, а потом удивляются лишним запросам, шуму в логах и лишней нагрузке. Полностью отключать API обычно плохая идея: Gutenberg, некоторые формы, мобильные приложения и внешние сервисы могут перестать работать. Рабочий подход — ограничить доступ для неавторизованных запросов и оставить нужные эндпоинты только там, где они реально используются.
Когда ограничение REST API действительно нужно
Типичный сценарий: сайт не использует публичный API, но в логах видны запросы к /wp-json/, а в отчётах по безопасности всплывают перечисления пользователей через /wp-json/wp/v2/users. Ещё один частый случай — API нужен только для админки и редактора, а внешним клиентам доступ не требуется. В такой конфигурации имеет смысл закрыть большую часть маршрутов для гостей и оставить исключения точечно.
Что именно стоит проверить до изменений
- Используется ли Gutenberg в админке и нет ли ошибок при открытии записей.
- Есть ли формы, которые отправляют данные через REST API.
- Подключены ли мобильные приложения, headless-фронтенд или внешние интеграции.
- Не завязаны ли плагины на публичные маршруты
wp-json.
Диагностика проблемы: какие запросы открыты сейчас
Перед правками полезно понять, какие маршруты доступны без авторизации. Самый простой способ — открыть главную страницу сайта и проверить ответ на /wp-json/. Если сервер возвращает JSON со списком маршрутов, это нормально. Вопрос в том, какие из них доступны гостям и не несут ли лишнюю информацию.
Для быстрой проверки можно использовать curl:
curl -I https://example.com/wp-json/wp/v2/usersЕсли маршрут отдаёт 200 OK без авторизации, это уже повод ограничить доступ. Если возвращается 401 или 403, значит защита уже работает на уровне ядра, плагина или сервера.
Ещё полезно проверить, не ломается ли редактор после ограничений. Именно здесь многие делают ошибку: закрывают весь REST API, а потом получают проблемы в админке, потому что Gutenberg и связанные компоненты не могут получать данные.
Как ограничить REST API кодом без отключения редактора
Самый предсказуемый вариант — добавить фильтр rest_authentication_errors в мини-плагин или в functions.php дочерней темы. Логика простая: если пользователь не авторизован, блокируем доступ ко всем маршрутам, кроме тех, которые вы явно разрешили.
<?php
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( is_user_logged_in() ) {
return $result;
}
$uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
$allowed_prefixes = array(
'/wp-json/',
);
// Разрешаем только конкретные маршруты, если они нужны гостям.
$allowed_routes = array(
'/wp-json/wp/v2/posts',
'/wp-json/wp/v2/pages',
);
foreach ( $allowed_routes as $route ) {
if ( strpos( $uri, $route ) === 0 ) {
return $result;
}
}
if ( strpos( $uri, '/wp-json/' ) === 0 ) {
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
}
return $result;
} );Этот пример намеренно простой. На практике лучше не полагаться на REQUEST_URI для сложной логики, если у вас много исключений. Но для типового сайта, где нужно закрыть публичные запросы и оставить только несколько маршрутов, решение работает предсказуемо.
Если нужен более точный контроль по маршрутам
Когда API используют отдельные плагины или внешние сервисы, удобнее проверять сам запрос через объект WP_REST_Request. Для этого можно перехватывать конкретные маршруты через rest_pre_dispatch и разрешать только нужные эндпоинты. Такой подход аккуратнее, но требует тестирования на реальных сценариях.
<?php
add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) {
if ( is_user_logged_in() ) {
return $result;
}
$route = $request->get_route();
$public_routes = array(
'/wp/v2/posts',
'/wp/v2/pages',
);
if ( in_array( $route, $public_routes, true ) ) {
return $result;
}
return new WP_Error(
'rest_forbidden',
__( 'Доступ к этому REST-методу ограничен.', 'textdomain' ),
array( 'status' => 401 )
);
}, 10, 3 );Здесь важно понимать: если вы ограничиваете маршруты слишком агрессивно, часть плагинов может начать падать не сразу, а только при выполнении конкретного действия. Поэтому после внедрения нужно пройтись по админке и по всем формам, которые есть на сайте.
Сравнение подходов: плагин, код или серверная блокировка
| Подход | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| Плагин безопасности | Нужна быстрая настройка без кода | Проще включить и откатить | Может давать слишком общие правила |
| Код в теме или мини-плагине | Нужны точные исключения | Гибкий контроль маршрутов | Требует тестирования и поддержки |
| Серверная блокировка | Нужно резать трафик до PHP | Меньше нагрузки на WordPress | Сложнее не сломать легитимные запросы |
Если задача только в том, чтобы убрать лишний шум и закрыть публичные пользовательские маршруты, кодовый вариант обычно удобнее. Если нужен жёсткий контроль на уровне Nginx или Apache, это уже отдельная история и там нужно учитывать конфигурацию хоста.
Пошаговая настройка без лишнего риска
- Сделайте резервную копию файлов и базы.
- Проверьте, какие плагины и функции используют REST API.
- Добавьте ограничение в мини-плагин, а не прямо в родительскую тему.
- Оставьте исключения для нужных публичных маршрутов.
- Проверьте вход в админку, Gutenberg, формы и интеграции.
- Посмотрите логи сервера и ответы
401/403на закрытые маршруты.
Мини-плагин здесь удобнее, чем правка functions.php: его проще отключить, если что-то пойдёт не так. Для рабочих сайтов это практичнее, чем вносить правки в тему и потом ловить проблему после обновления.
Как проверить, что ограничение сработало
Проверка должна быть не только технической, но и прикладной. Сначала убедитесь, что закрытые маршруты действительно перестали отвечать гостям. Затем проверьте, что авторизованный пользователь по-прежнему может работать с админкой и редактором.
- Откройте
/wp-json/wp/v2/usersв режиме инкогнито. - Проверьте
/wp-json/wp/v2/postsи другие разрешённые маршруты. - Создайте или отредактируйте запись в Gutenberg.
- Отправьте форму, если она использует REST-запросы.
- Посмотрите, нет ли новых ошибок в
debug.logили логах веб-сервера.
Если сайт использует кэш или CDN, не забудьте очистить их после изменений. Иначе можно проверить старую версию ответа и сделать неверный вывод, что защита не сработала.
Частые ошибки и как их исправить
Полностью закрыли весь REST API
Это самая частая ошибка. После такой правки редактор может начать вести себя нестабильно, а некоторые плагины — перестать сохранять данные. Исправление простое: не блокируйте всё подряд, а оставьте разрешённые маршруты для нужных сценариев.
Проверяют только главную страницу, а не конкретные маршруты
То, что /wp-json/ открывается, ещё не означает, что всё плохо. Важно смотреть конкретные эндпоинты, особенно users, пользовательские маршруты плагинов и публичные методы, которые отдают чувствительные данные.
Вносят правки в родительскую тему
После обновления темы ограничение исчезает. Для таких задач лучше использовать мини-плагин или mu-plugin. Это надёжнее и не зависит от дизайна сайта.
Не тестируют авторизованные сценарии
Ограничение может быть безопасным для гостей, но ломать сохранение записей или интеграцию с формой. Поэтому проверка должна идти от реального сценария, а не только от ответа 401 в браузере.
Практические советы по безопасности и производительности
Если цель — уменьшить поверхность атаки, одного REST API обычно недостаточно. Имеет смысл одновременно проверить XML-RPC, список пользователей, индексацию технических страниц и лишние публичные маршруты плагинов. Но не стоит отключать всё подряд без анализа: иногда именно публичный маршрут нужен для нормальной работы сайта.
Для сайтов, где важна техническая чистота, полезно держать под рукой инструменты, которые помогают убирать дубли и лишние служебные элементы. Например, Clearfy Pro уместен там, где нужно последовательно навести порядок в SEO, дублях и технических настройках без ручной правки каждого шаблона. Если же вы работаете через код, всё равно сначала проверяйте, что именно использует API, а уже потом режьте доступ.
И ещё один практический момент: если вы закрываете REST API на уровне PHP, не забывайте про нагрузку. Чем раньше запрос будет отклонён, тем лучше. Но если правила слишком сложные и выполняются на каждом обращении, выигрыш может оказаться меньше ожидаемого.