REST API в WordPress часто нужен не только редактору и админке, но и теме, блокам, формам, поиску, мобильным приложениям и сторонним сервисам. Поэтому задача обычно не в том, чтобы «выключить всё», а в том, чтобы закрыть доступ для гостей там, где он реально не нужен. Если сделать это грубо, можно получить неработающие блоки, ошибки в консоли и проблемы у плагинов, которые ожидают ответы из /wp-json/.
Ниже — практический сценарий: как ограничить REST API для незалогиненных пользователей, не ломая вход в админку и не создавая лишних 403 там, где они не нужны.
Когда REST API действительно стоит ограничить
Полное отключение REST API — редкая и обычно плохая идея. Гораздо чаще нужно убрать доступ для гостей к данным, которые не должны быть доступны без авторизации: спискам пользователей, внутренним типам записей, метаданным, служебным endpoint’ам плагинов. При этом публичные запросы, которые использует фронтенд, должны продолжать работать.
Типичный сигнал, что ограничение уместно:
- в логах видны частые запросы к
/wp-json/wp/v2/usersили похожим endpoint’ам от ботов; - на сайте нет фронтенд-функций, завязанных на REST API для гостей;
- нужно снизить поверхность атаки без вмешательства в тему и плагины;
- на проекте есть требования по минимизации публичных технических точек доступа.
Диагностика: что именно использует REST API на сайте
Перед ограничением проверьте, какие запросы идут с фронтенда. Самая частая ошибка — заблокировать всё подряд и потом искать причину сломанного поиска, редактора блоков или виджета. Откройте сайт в браузере, перейдите в DevTools и посмотрите вкладку Network с фильтром fetch или xhr. Если видите запросы к /wp-json/ при загрузке страницы, их нужно учесть.
Дополнительно проверьте, не использует ли REST API:
- поиск по сайту через AJAX;
- блоки Gutenberg на фронтенде;
- формы, которые отправляют данные через endpoint плагина;
- мобильное приложение WordPress;
- интеграции с внешними сервисами, если они работают через REST.
Что смотреть в логах и консоли
Если после тестового ограничения появляются ошибки, обычно это видно сразу:
- в консоли браузера —
401или403на запросы к/wp-json/; - в HTML — сломанные блоки, которые не подгружают данные;
- в логах сервера — всплеск запросов к закрытым endpoint’ам;
- в админке — проблемы с редактором блоков, если ограничение сделано слишком агрессивно.
Как ограничить REST API для гостей кодом
Самый безопасный вариант — не отключать REST API целиком, а запретить доступ гостям только к неразрешённым endpoint’ам. Для этого удобно использовать фильтр rest_authentication_errors. Он срабатывает до выполнения запроса и позволяет вернуть ошибку для незалогиненных пользователей.
Пример: разрешаем публичные маршруты, а всё остальное закрываем для гостей.
<?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 ) {
// Здесь лучше заменить на более точечную проверку маршрутов,
// если на сайте есть публичные REST-эндпоинты.
return $result;
}
}
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
} );
Этот пример намеренно простой, но в таком виде он не подходит для всех сайтов. На практике лучше не ориентироваться на REQUEST_URI как на единственный критерий, а точечно разрешать нужные маршруты. Если на сайте есть публичные endpoint’ы, их стоит перечислить отдельно.
Более точечный вариант: разрешить только нужные маршруты
Если вы знаете, какие маршруты должны работать для гостей, безопаснее проверять сам запрос REST API. В WordPress это можно сделать через rest_pre_dispatch или rest_authentication_errors, но для большинства задач достаточно фильтра на этапе аутентификации.
<?php
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) || is_user_logged_in() ) {
return $result;
}
$route = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
$public_routes = array(
'/wp-json/wp/v2/posts',
'/wp-json/wp/v2/pages',
);
foreach ( $public_routes as $public_route ) {
if ( strpos( $route, $public_route ) !== false ) {
return $result;
}
}
return new WP_Error( 'rest_forbidden', 'REST API закрыт для гостей.', array( 'status' => 401 ) );
} );
Если сайт большой, лучше вынести список разрешённых маршрутов в отдельную функцию или конфиг, чтобы не править код в нескольких местах.
Сравнение подходов: плагин, код, серверная блокировка
| Подход | Плюсы | Минусы | Когда выбирать |
|---|---|---|---|
Код в functions.php или mu-plugin | Точечный контроль, без лишних зависимостей | Нужно понимать маршруты и тестировать | Когда нужен аккуратный контроль доступа |
| Плагин безопасности | Быстро включить, меньше ручной работы | Не всегда есть нужная гранулярность | Если нужен простой интерфейс для администратора |
| Блокировка на уровне сервера | Снижает нагрузку на PHP | Легко сломать легитимные запросы | Когда REST API не нужен гостям вообще |
Если нужен именно технический контроль, код обычно предсказуемее. Если задача организационная и сайт поддерживает не разработчик, удобнее использовать плагин с понятными настройками. Для проектов, где важна чистка лишнего и контроль технических дублей, иногда используют набор инструментов вроде Clearfy Pro, но даже в этом случае правило одно: сначала проверить, какие маршруты реально нужны сайту, и только потом ограничивать доступ.
Пошаговое внедрение без сюрпризов
- Сделайте резервную копию файлов и базы.
- Проверьте, какие запросы к
/wp-json/идут на главной, в записях и в админке. - Добавьте ограничение сначала на тестовом сайте или в staging.
- Откройте сайт в обычном браузере без авторизации и проверьте фронтенд.
- Зайдите в админку, откройте редактор блоков и убедитесь, что он работает.
- Проверьте формы, поиск, фильтры и любые AJAX-виджеты.
- Посмотрите логи сервера и консоль браузера на предмет 401/403.
Как проверить, что решение сработало
Проверка должна быть не формальной, а по факту поведения сайта. Откройте в браузере адрес /wp-json/ и несколько конкретных маршрутов, которые раньше были доступны. Для гостя закрытые endpoint’ы должны возвращать ошибку доступа, а публичные — работать как раньше.
Минимальный набор проверок:
- страницы сайта открываются без ошибок;
- редактор блоков в админке работает;
- формы и AJAX-элементы не сломались;
- закрытые REST-маршруты для гостя возвращают
401или403; - в консоли нет новых ошибок, связанных с
/wp-json/.
Если есть доступ к терминалу, можно быстро проверить ответ через curl:
curl -I https://example.com/wp-json/wp/v2/usersДля закрытого маршрута вы должны увидеть не успешный ответ. Если вместо этого приходит 200, ограничение не сработало или маршрут разрешён другим правилом.
Частые ошибки и как их исправить
Отключили REST API целиком
Это самая грубая ошибка. В результате ломаются блоки, интеграции и часть фронтенд-логики. Исправление простое: не отключайте API полностью, а ограничьте только нужные маршруты или только гостей.
Проверяют только главную страницу
На главной всё может выглядеть нормально, а в записи с блоками или в форме поиска уже появятся ошибки. Тестировать нужно несколько типов страниц: главную, запись, страницу с формой, страницу с AJAX-фильтром, админку.
Используют слишком общий паттерн для URL
Если фильтр завязан на грубую проверку строки, можно случайно закрыть нужный маршрут. Лучше перечислять разрешённые endpoint’ы явно и не полагаться на совпадение по подстроке без необходимости.
Забывают про кэш и CDN
После изменения логики REST API старые ответы могут ещё отдаваться из кэша. Очистите кэш плагина, серверный кэш и CDN, если он есть. Иначе будет казаться, что код не работает, хотя на самом деле вы видите старый ответ.
Безопасность и производительность: что учесть дополнительно
Ограничение REST API для гостей не заменяет нормальную защиту админки и не делает сайт «закрытым». Это лишь один слой. Если цель — уменьшить поверхность атаки, имеет смысл дополнительно проверить:
- не светятся ли в публичном доступе лишние пользовательские данные;
- не доступны ли служебные endpoint’ы плагинов без авторизации;
- не создаёт ли ограничение лишнюю нагрузку из-за постоянных 401 на фронтенде;
- не нужен ли отдельный whitelist для интеграций.
Если проект поддерживается командой без постоянного разработчика, лучше оформить ограничение как маленький mu-plugin, а не как правку в теме. Так правило не потеряется при обновлении темы и его проще сопровождать.
<?php
/**
* Plugin Name: REST API Restriction
*/
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) || is_user_logged_in() ) {
return $result;
}
$route = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
if ( strpos( $route, '/wp-json/wp/v2/posts' ) !== false ) {
return $result;
}
return new WP_Error( 'rest_forbidden', 'REST API закрыт для гостей.', array( 'status' => 401 ) );
} );
Такой подход проще откатить, чем правки в functions.php, и он меньше зависит от темы.