REST API в WordPress часто оставляют открытым по умолчанию, а потом удивляются лишним запросам к /wp-json/, шуму в логах и нежелательному сбору данных о сайте. Но закрывать его «в лоб» нельзя: редактор блоков, мобильные приложения, некоторые формы, интеграции и плагины тоже ходят в REST. Поэтому задача не в том, чтобы выключить API целиком, а в том, чтобы ограничить доступ для неавторизованных пользователей и не сломать рабочие сценарии.
Ниже — рабочий вариант для типичного сайта на WordPress: сначала диагностика, потом точечное ограничение, затем проверка результата и список ошибок, которые чаще всего ломают админку или фронтенд.
Когда REST API действительно стоит ограничить
Не каждый сайт нуждается в полном открытии REST API. Если у вас обычный корпоративный сайт, блог или контентный проект без внешнего приложения, то публичный доступ к части эндпоинтов часто не нужен. Проблема обычно проявляется в одном из сценариев:
- в логах много запросов к
/wp-json/wp/v2/от ботов и парсеров; - в выдаче и аналитике видны обращения к JSON-эндпоинтам;
- плагины безопасности ругаются на избыточно открытые маршруты;
- нужно скрыть служебные данные о записях, авторах, таксономиях и медиа;
- сайт не использует headless-архитектуру, мобильное приложение или внешнюю интеграцию через REST.
Если у вас есть фронтенд на React/Vue, мобильное приложение, интеграция с CRM или автоматизация через REST, закрывать API целиком не нужно. В таком случае ограничивают только публичные маршруты или добавляют авторизацию.
Диагностика: что именно сейчас открыто
Перед правкой кода стоит понять, какие эндпоинты доступны без авторизации. Самый простой способ — открыть в браузере /wp-json/ и несколько типовых маршрутов. Если сайт отдает JSON с описанием маршрутов, это нормально. Вопрос в том, что именно доступно гостю.
Проверка через браузер и curl
Проверьте несколько адресов:
https://example.com/wp-json/https://example.com/wp-json/wp/v2/postshttps://example.com/wp-json/wp/v2/usersДля быстрой проверки из консоли удобно использовать curl:
curl -I https://example.com/wp-json/wp/v2/postsЕсли ответ 200 OK и JSON отдается без входа в админку, маршрут публичный. Для некоторых сайтов это допустимо, но если вы не хотите светить структуру контента, лучше ограничить доступ.
Что нельзя ломать
WordPress-редактор блоков использует REST API для сохранения и загрузки контента. Если вы отключите его без исключений, получите ошибки в редакторе, автосохранении и загрузке медиа. Поэтому решение должно учитывать авторизованных пользователей и, как минимум, админов и редакторов.
Пошаговое решение: ограничить REST API для гостей
Самый предсказуемый способ — добавить фильтр rest_authentication_errors и возвращать ошибку только для неавторизованных пользователей. Так вы не трогаете внутренние запросы WordPress и не ломаете работу редактора для вошедших пользователей.
<?php
add_filter( 'rest_authentication_errors', function ( $result ) {
// Если уже есть ошибка аутентификации, не перезаписываем её.
if ( ! empty( $result ) ) {
return $result;
}
// Авторизованным пользователям REST нужен для редактора и админки.
if ( is_user_logged_in() ) {
return $result;
}
// Разрешаем только базовый индекс, если он нужен для диагностики.
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
if ( strpos( $request_uri, '/wp-json/' ) === 0 && $request_uri === '/wp-json/' ) {
return $result;
}
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
} );Код можно добавить в functions.php дочерней темы, но для технически аккуратного проекта лучше вынести его в небольшой mu-plugin. Тогда он не пропадет при смене темы.
Вариант через mu-plugin
Создайте файл wp-content/mu-plugins/restrict-rest-api.php и положите туда код. Если папки mu-plugins нет, создайте её вручную.
<?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;
}
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
} );Этот вариант проще сопровождать: код не зависит от темы, а отключение сводится к удалению одного файла.
Если нужно закрыть только часть маршрутов
Иногда целиком блокировать REST API не нужно. Например, вы хотите скрыть пользователей, но оставить посты, страницы и медиа для публичных запросов. Тогда лучше фильтровать конкретные маршруты через rest_endpoints.
<?php
add_filter( 'rest_endpoints', function ( $endpoints ) {
if ( is_user_logged_in() ) {
return $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, сначала протестируйте на staging-окружении.
Сравнение подходов
| Подход | Что делает | Плюсы | Минусы |
|---|---|---|---|
| Полная блокировка для гостей | Закрывает REST API для неавторизованных | Просто, быстро, снижает шум | Может сломать публичные интеграции |
| Ограничение отдельных маршрутов | Скрывает только выбранные эндпоинты | Точнее, меньше рисков | Нужно знать зависимости плагинов |
| Оставить API и настроить авторизацию | Не закрывает API, но требует токены/куки | Подходит для интеграций и headless | Сложнее в поддержке |
Как проверить, что решение сработало
Проверка должна быть не только визуальной. После внедрения откройте несколько адресов и убедитесь, что поведение изменилось именно так, как вы планировали.
/wp-json/— если вы оставили индекс открытым, он должен отвечать как раньше;/wp-json/wp/v2/posts— для гостя должен вернуться401или другой ожидаемый статус;- в редакторе записей под авторизованным пользователем сохранение должно работать без ошибок;
- если есть формы, интеграции или мобильное приложение, проверьте их отдельно;
- посмотрите error log и консоль браузера на предмет новых ошибок REST.
Для быстрой проверки статуса можно использовать:
curl -i https://example.com/wp-json/wp/v2/postsЕсли вы ограничивали только отдельные маршруты, проверьте именно их. Не полагайтесь на один запрос к индексу /wp-json/: он не показывает, что происходит с конкретными endpoint'ами.
Частые ошибки и как их исправить
Сломали Gutenberg у редакторов
Обычно это происходит, когда блокировка применяется ко всем запросам без учета авторизации. Решение простое: не ограничивайте REST для вошедших пользователей. Если проблема уже появилась, временно отключите код и проверьте, не добавлен ли он в тему вместо mu-plugin.
Закрыли API, но JSON всё равно доступен
Некоторые плагины или серверные правила могут отдавать кешированную версию ответа. Очистите кеш плагина, серверный кеш и CDN. Если используется Nginx или Cloudflare, проверьте, не кэшируется ли /wp-json/ на уровне прокси.
Появились ошибки у внешнего сервиса
Значит, сервис действительно использовал REST без авторизации. В этом случае не стоит «чинить» проблему полным открытием API. Лучше выделить отдельный маршрут, настроить токен или использовать прикладную авторизацию, если сервис это поддерживает.
Ограничение добавили в тему, а потом забыли
Это типичная ошибка сопровождения. При смене темы защита исчезнет. Для технических правил безопасности лучше использовать mu-plugin или отдельный мини-плагин.
Практические советы по безопасности и производительности
Если цель — снизить поверхность атаки и лишнюю нагрузку, одного ограничения REST API может быть мало. Посмотрите на сопутствующие вещи:
- не кэшируйте ответы REST без понимания, какие данные там отдаются;
- проверьте, не индексируются ли JSON-URL в поиске через внешние ссылки и sitemap;
- убедитесь, что сервер не отдает лишние заголовки и не раскрывает версию WordPress;
- если сайт большой, тестируйте изменения на копии, а не на боевом домене;
- после правки кода всегда проверяйте админку, редактор и формы обратной связи.
Если вам нужен более широкий набор технических настроек для чистки WordPress от дублей и лишних служебных запросов, удобно держать всё в одном месте. В таких задачах часто используют Clearfy Pro: https://wpshop.ru/plugins/clearfy. Но даже с плагином полезно понимать, какой именно маршрут вы закрываете и почему.
Если нужен более мягкий режим
Иногда правильнее не блокировать REST API, а ограничить его видимость для гостей и оставить только то, что реально используется. Например, можно скрыть пользователей, убрать лишние маршруты плагинов и оставить публичные записи. Такой подход требует больше ручной проверки, зато меньше шансов сломать интеграцию, о которой уже забыли.
Практически это сводится к двум вопросам: кто должен иметь доступ и какие маршруты действительно нужны. Если ответов нет, начинайте с staging-копии и включайте ограничение постепенно, а не одним большим коммитом.