Публичный REST API в WordPress часто нужен для Gutenberg, мобильных приложений, интеграций и некоторых плагинов. Но на обычном сайте он же может быть лишним источником лишних запросов, утечек служебных данных и шума в логах. Если задача не в том, чтобы «выключить всё», а в том, чтобы закрыть доступ для неавторизованных запросов, это лучше делать точечно.
Ниже — рабочий сценарий: сначала проверяем, что именно открыто, затем ограничиваем доступ только для гостей, и в конце убеждаемся, что редактор и нужные интеграции не сломались.
Когда REST API действительно стоит ограничить
Не каждый сайт должен прятать REST API целиком. Если у вас есть фронтенд на React, мобильное приложение, headless-схема или плагины, которые ходят в /wp-json/, полное отключение создаст больше проблем, чем пользы. Но если сайт обычный: статьи, страницы, формы, без внешних клиентов и без публичных API-эндпоинтов, ограничение неавторизованных запросов обычно оправдано.
Что обычно видно в диагностике
- в логах много запросов к
/wp-json/wp/v2/posts,/wp-json/wp/v2/usersи похожим маршрутам; - сканеры безопасности показывают доступность REST API для гостей;
- некоторые плагины используют REST только внутри админки, а снаружи он не нужен;
- на сайте есть лишняя индексация служебных URL, хотя сами данные не критичны.
Важно понимать: сам по себе открытый REST API не означает уязвимость. Проблема начинается там, где гостям доступны данные, которые вы не хотите отдавать наружу, или где публичные запросы создают ненужную нагрузку.
Диагностика: что именно доступно сейчас
Перед изменениями проверьте базовые точки. Это занимает пару минут и помогает не ломать то, что уже работает.
https://example.com/wp-json/Если в ответе виден список маршрутов, это нормально. Дальше смотрим, что доступно без авторизации. Например, такие запросы часто возвращают данные публично:
https://example.com/wp-json/wp/v2/posts?per_page=1
https://example.com/wp-json/wp/v2/pages?per_page=1А вот маршруты, связанные с пользователями, на некоторых сайтах лучше не светить лишний раз. Проверяйте не только сам факт ответа, но и его содержимое.
Если у вас есть доступ к серверным логам, полезно посмотреть, кто и как часто ходит в REST. Иногда оказывается, что основной шум создают не поисковики, а сторонние боты и сканеры.
Как ограничить REST API только для неавторизованных пользователей
Самый безопасный путь — не отключать REST API глобально, а блокировать его для гостей через фильтр rest_authentication_errors. Это штатный механизм WordPress, и он позволяет оставить доступ авторизованным пользователям и внутренним запросам.
Вариант через functions.php или мини-плагин
Лучше не вносить это в тему, если сайт живёт на готовой теме и вы не хотите терять правку при обновлении. Надёжнее — маленький must-use плагин или обычный плагин для технических настроек.
<?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;
}
// Разрешаем только запросы из админки, если они уже авторизованы cookie/nonce.
// Для гостей возвращаем ошибку доступа.
return new WP_Error(
'rest_forbidden',
__( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
array( 'status' => 401 )
);
} );Этот вариант жёсткий: все неавторизованные REST-запросы получают отказ. Он подходит не всем. Если у вас есть публичные маршруты, которые должны работать для гостей, нужно делать исключения.
Более аккуратный вариант с исключением для нужных маршрутов
Если сайт использует публичные эндпоинты, например для формы, поиска или внешней интеграции, лучше ограничивать только часть маршрутов. Ниже пример, где разрешён доступ к конкретным путям, а всё остальное закрыто для гостей.
<?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/wp/v2/posts',
'/wp-json/wp/v2/pages',
'/wp-json/my-plugin/v1/public',
);
foreach ( $allowed_prefixes as $prefix ) {
if ( str_starts_with( $request_uri, $prefix ) ) {
return $result;
}
}
return new WP_Error(
'rest_forbidden',
__( 'REST API закрыт для неавторизованных запросов.', 'textdomain' ),
array( 'status' => 401 )
);
} );Здесь есть важный нюанс: проверка по REQUEST_URI грубая. Она подходит для простых случаев, но если у вас сложная схема маршрутов, лучше проверять сам REST-запрос через rest_pre_dispatch или строить белый список на уровне конкретных эндпоинтов плагина.
Сравнение подходов: плагин, код, сервер
| Подход | Что делает | Плюсы | Минусы |
|---|---|---|---|
Код через rest_authentication_errors | Блокирует гостей в WordPress | Точно, гибко, без лишних зависимостей | Нужно тестировать исключения |
| Плагин безопасности | Даёт готовые настройки | Быстро включить, меньше ручной работы | Не всегда есть нужная гранулярность |
| .htaccess / nginx | Режет доступ на уровне веб-сервера | Снимает нагрузку раньше PHP | Легко сломать редактор и интеграции |
Если нужен именно практический контроль, я бы начинал с кода в WordPress. Серверные правила стоит использовать только когда вы точно понимаете, какие маршруты должны остаться доступными.
Что проверить после внедрения
После изменения не ограничивайтесь одной ручной проверкой в браузере. Нужны минимум три теста: гостевой доступ, авторизованный доступ и работа редактора.
- Откройте
/wp-json/в режиме инкогнито — должен быть отказ или ограниченный ответ, если вы закрыли API полностью. - Проверьте
/wp-json/wp/v2/posts?per_page=1— если этот маршрут должен быть публичным, он обязан отвечать. - Зайдите в админку и откройте редактор записи — сохранение и автосохранение не должны ломаться.
- Если есть формы, поиск или внешние сервисы, проверьте их отдельно.
Для быстрой проверки можно использовать curl:
curl -I https://example.com/wp-json/
curl -I https://example.com/wp-json/wp/v2/posts?per_page=1Если в ответе для гостей вы видите 401 или 403 там, где ожидали блокировку, это нормально. Если же редактор начал выдавать ошибки сохранения, значит вы закрыли слишком много.
Частые ошибки и как их исправить
Сломали Gutenberg или автосохранение
Это самая частая проблема после грубого отключения REST API через .htaccess или серверные правила. Редактор WordPress активно использует REST для сохранения и получения данных. Если закрыть всё подряд, админка перестанет работать корректно.
Решение: уберите серверную блокировку и перенесите ограничение в WordPress-слой, где можно оставить доступ авторизованным пользователям.
Закрыли публичные маршруты, которые нужны теме или плагину
Некоторые темы и плагины используют публичные REST-эндпоинты для вывода контента, фильтров или виджетов. Если после блокировки на фронтенде пропали данные, проверьте, какой маршрут вызывает проблему, и добавьте его в исключения.
Проверяли только в админке
В админке всё может выглядеть нормально, а для гостей API уже закрыт слишком жёстко. Обязательно тестируйте в инкогнито или через curl, иначе легко пропустить поломку публичной части сайта.
Ориентировались только на robots.txt
Запись в robots.txt не закрывает доступ. Она лишь просит поисковики не индексировать URL. Если задача именно в ограничении доступа, нужен код, серверное правило или плагин безопасности.
Практические советы по безопасности и производительности
Если цель — уменьшить поверхность атаки и лишний шум, не ограничивайтесь только REST API. Посмотрите на соседние точки: xmlrpc.php, публичные авторские архивы, лишние таксономии и служебные страницы. Но не смешивайте всё в одну правку: так проще понять, что именно сломалось.
- вносите изменения в отдельный мини-плагин, а не в тему;
- перед обновлениями сохраняйте копию файла с правкой;
- если используете кеширующий плагин, очистите кеш после изменения правил доступа;
- не закрывайте REST API на staging без проверки интеграций, если потом переносите конфиг на production.
Если вам нужен более широкий набор технических настроек — от дублей и индексации до чистки сайта и служебных ограничений — такие задачи удобно держать в одном месте, например через Clearfy Pro: https://wpshop.ru/plugins/clearfy. Но даже в этом случае логику доступа лучше проверять вручную, а не полагаться только на чекбокс.
Если нужен не просто запрет, а точечное управление доступом, рабочая схема обычно такая: определить нужные маршруты, закрыть лишнее через rest_authentication_errors, протестировать гостевой и авторизованный сценарий, затем уже смотреть на серверные оптимизации. Это даёт контроль без лишнего риска для админки и редактора.