WP REST API часто оставляют открытым по умолчанию, а потом удивляются лишним запросам к /wp-json/, светящимся пользователям в ответах и шуму в логах. Полностью отключать REST API обычно плохая идея: Gutenberg, некоторые темы, мобильные приложения и плагины используют его легально. Но если задача узкая — убрать публичную выдачу данных для гостей, не ломая авторизованные сценарии, — это можно сделать аккуратно.
Ниже разберём рабочий вариант для типичного сайта на WordPress: скрыть публичные маршруты REST API для неавторизованных пользователей, оставить доступ админам и не трогать внутренние запросы редактора.
Когда проблема реально есть
Сначала стоит понять, что именно вы хотите закрыть. Не каждый запрос к REST API — это угроза. На практике проблема возникает в трёх сценариях:
- в ответах
/wp-json/wp/v2/usersвидны логины или метаданные пользователей; - боты массово дергают
/wp-json/и создают лишнюю нагрузку; - внешние сервисы не должны получать структуру сайта, но API открыт для всех.
Если у вас работает блоковый редактор, формы, headless-фронтенд или интеграции через REST, отключать всё подряд нельзя. В таких случаях лучше ограничивать только публичные маршруты, а не сам механизм.
Что проверить до изменений
- Откройте
/wp-json/в браузере и посмотрите, отдаёт ли сайт индекс маршрутов. - Проверьте
/wp-json/wp/v2/usersи похожие публичные endpoints. - Посмотрите логи веб-сервера: есть ли всплеск запросов к
/wp-json/. - Убедитесь, что редактор Gutenberg и админка работают в обычном режиме.
Как закрыть публичный REST API через код
Самый предсказуемый способ — добавить фильтр rest_authentication_errors. Он позволяет вернуть ошибку для гостей, но не мешает авторизованным пользователям и внутренним вызовам, если настроить его аккуратно.
Добавлять код лучше в мини-плагин или в functions.php дочерней темы. Для продакшена мини-плагин надёжнее: он не зависит от темы.
<?php
/**
* Plugin Name: Restrict Public REST API
*/
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'] ) : '';
if ( strpos( $uri, '/wp-json/wp/v2/posts' ) !== false ) {
return $result;
}
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.' ),
array( 'status' => 403 )
);
} );Этот пример намеренно жёсткий. Он блокирует гостей почти полностью. Если вам нужно оставить доступ к постам, страницам или конкретному плагинному маршруту, список разрешений лучше сделать явным и коротким.
Более безопасный вариант: блокировать только чувствительные маршруты
Если цель — убрать утечку пользователей и служебных данных, не закрывайте весь API. Достаточно ограничить отдельные endpoints. Это меньше ломает сайт и проще сопровождать.
<?php
add_filter( 'rest_endpoints', function( $endpoints ) {
if ( is_user_logged_in() ) {
return $endpoints;
}
unset( $endpoints['/wp/v2/users'] );
unset( $endpoints['/wp/v2/users/(?P<id>[\\d]+)'] );
return $endpoints;
} );Такой подход не отключает REST API целиком, а просто убирает самые чувствительные маршруты для гостей. Для многих сайтов этого достаточно.
Если нужен серверный уровень: что можно сделать в Nginx или Apache
Серверные правила полезны, когда нужно отрезать шум ещё до загрузки WordPress. Но здесь важно не переусердствовать: если вы заблокируете /wp-json/ без оглядки, можете сломать фронтенд, редактор или внешние интеграции.
| Подход | Плюс | Минус |
|---|---|---|
| PHP-фильтр | Точечный контроль, проще тестировать | WordPress всё равно загружается |
| Nginx/Apache правило | Меньше нагрузки на сервер | Легко заблокировать лишнее |
| Плагин безопасности | Быстро включить без кода | Зависимость от сторонней логики |
Если вы уверены, что публичный REST API не нужен вообще, можно вернуть 403 на уровне веб-сервера. Для Nginx это выглядит так:
location ~* ^/wp-json/ {
return 403;
}Для Apache можно использовать правило в .htaccess, но только если вы понимаете последствия и у вас нет сценариев, завязанных на REST API:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/wp-json/ [NC]
RewriteRule .* - [F,L]
</IfModule>Серверный вариант хорош для жёсткого ограничения, но для большинства сайтов безопаснее начинать с PHP-уровня и только потом, если нужно, переносить ограничение ниже.
Проверка результата после внедрения
После правки не ограничивайтесь открытием главной страницы. Проверьте именно те точки, которые обычно ломаются первыми.
- Откройте
/wp-json/в режиме инкогнито: должен быть 403 или минимальный ответ, если вы оставили публичный доступ. - Проверьте
/wp-json/wp/v2/users: он не должен отдавать список пользователей гостю. - Зайдите в админку и откройте редактор записи: сохранение и автосохранение должны работать.
- Если есть формы, AJAX или внешние интеграции, протестируйте их отдельно.
- Посмотрите error log и access log: не должно быть лавины 403 от нужных внутренних запросов.
Хороший практический тест — открыть страницу с блоковым редактором, внести правку, сохранить и проверить, не появились ли ошибки в консоли браузера. Если REST API нужен редактору, он должен продолжать отвечать для авторизованной сессии.
Частые ошибки и как их исправить
Закрыли весь REST API и сломали редактор
Это самая частая ошибка. Gutenberg и часть плагинов используют REST API для сохранения контента, подгрузки данных и проверки состояния. Если после блокировки редактор начал выдавать ошибки, откатите жёсткое правило и перейдите к точечному ограничению маршрутов.
Использовали слишком широкий серверный фильтр
Правило вида location /wp-json/ { return 403; } без проверки сценариев может задеть легитимные запросы. Перед применением убедитесь, что у вас нет headless-фронтенда, мобильного приложения или интеграции с внешним сервисом.
Скрыли только часть маршрутов, но оставили утечку пользователей
Если цель — убрать перечисление пользователей, проверьте не только /wp/v2/users, но и связанные endpoints, которые могут светить данные через метаданные или авторские архивы. Иногда проблема решается не блокировкой API, а ограничением прав на просмотр профилей и отключением лишних полей в ответе.
Не проверили кэш
Если на сайте стоит кэширующий плагин или CDN, старый ответ /wp-json/ может ещё какое-то время отдаваться из кэша. После изменений очистите кэш плагина, серверный кэш и CDN, если он есть.
Практические советы по безопасности и производительности
Если вы ограничиваете REST API ради безопасности, не останавливайтесь только на этом. Проверьте ещё несколько вещей:
- уберите лишние данные из ответов пользователей и записей, если они не нужны;
- ограничьте доступ к чувствительным endpoints точечно, а не целиком;
- не используйте плагины, которые отключают REST API без разбора, если сайт зависит от редактора;
- после изменений мониторьте 403 в логах хотя бы несколько дней.
Если нужен более широкий набор инструментов для чистки сайта, отключения дублей и технической оптимизации, иногда удобнее собрать это в одном решении, чем держать россыпь мелких правок. Но даже в этом случае проверяйте, какие именно маршруты и функции оно затрагивает, прежде чем включать на боевом сайте.
Для сайтов, где REST API нужен только частично, лучший сценарий обычно такой: сначала точечная блокировка чувствительных endpoints через код, затем проверка логов и только потом, при необходимости, усиление правила на уровне сервера.