Как ограничить JSON REST API в WordPress для неавторизованных запросов

REST API в WordPress часто оставляют открытым «по умолчанию», а потом удивляются лишним запросам, шуму в логах и нежелательному сбору данных о сайте. Полностью отключать API обычно плохая идея: редактор блоков, мобильные приложения, некоторые плагины и внешние интеграции используют его легально. На практике чаще нужен не запрет всего подряд, а ограничение доступа для неавторизованных запросов.

Ниже разберём рабочий сценарий: что именно ограничивать, как не сломать сайт, чем отличается код от плагина и как проверить, что всё действительно сработало.

Когда REST API стоит ограничивать

Сначала полезно понять, есть ли у вас реальная проблема. Если в логах много запросов к /wp-json/, а на сайте нет публичных сценариев, где API нужен гостям, ограничение оправдано. Типичные сигналы:

  • в access log регулярно идут запросы к /wp-json/wp/v2/posts, /wp-json/wp/v2/users и похожим маршрутам;
  • сканеры и боты получают через API список записей, рубрик и авторов;
  • на хостинге растёт число запросов к JSON-эндпоинтам без видимой пользы;
  • внешние сервисы работают только после авторизации, а гостевой доступ не нужен.

Если у вас включён блоковый редактор, не стоит рубить API целиком. Gutenberg и часть админки используют REST-запросы для сохранения и загрузки данных. Поэтому задача обычно звучит так: оставить API для авторизованных пользователей и нужных внутренних запросов, а гостям вернуть 401 или 403.

Быстрая диагностика: что именно открыто

Перед изменениями проверьте, как ведёт себя API сейчас. Самый простой тест — открыть базовый маршрут в браузере или через curl.

curl -I https://example.com/wp-json/

Если сервер отвечает 200 OK и отдаёт JSON, API доступен. Это ещё не ошибка, но повод проверить, какие маршруты реально нужны без авторизации. Для более точной диагностики полезно посмотреть:

  • какие эндпоинты вызываются чаще всего;
  • есть ли обращения к /wp-json/wp/v2/users — этот маршрут часто используют для перечисления авторов;
  • не завязаны ли на REST сторонние формы, поиск, фронтенд-виджеты или headless-интеграции.

Если сомневаетесь, временно включите логирование на уровне веб-сервера или проверьте журнал безопасности в плагине. Важно не гадать, а увидеть, что именно запрашивают.

Рабочие варианты ограничения REST API

Есть три практических подхода: плагин, код в теме или mu-plugin, и ограничение на уровне сервера. У каждого свой компромисс.

СпособПлюсыМинусы
ПлагинБыстро, без правок темы, проще откатитьЗависимость от стороннего кода, лишняя нагрузка
Код в functions.php или mu-pluginКонтроль, предсказуемость, легко точечно исключать маршрутыНужна аккуратность и тестирование
Правила сервераСрабатывает рано, снижает шум до WordPressСложнее поддерживать, легко сломать нужные маршруты

Для большинства сайтов самый безопасный путь — небольшой код с исключениями. Он позволяет оставить доступ для авторизованных пользователей и при этом закрыть гостевой доступ.

Вариант 1. Ограничить REST API для гостей кодом

Добавьте код в functions.php дочерней темы или, лучше, в отдельный mu-plugin. Этот вариант блокирует неавторизованные запросы, но не мешает входу в админку и работе авторизованных сессий.

<?php
add_filter( 'rest_authentication_errors', function ( $result ) {
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    if ( is_user_logged_in() ) {
        return $result;
    }

    // Разрешаем только те маршруты, которые вы явно хотите оставить открытыми.
    $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';

    if ( strpos( $request_uri, '/wp-json/' ) !== false ) {
        return new WP_Error(
            'rest_forbidden',
            __( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
            array( 'status' => 401 )
        );
    }

    return $result;
} );

Этот пример намеренно простой. Если у вас есть публичные маршруты, например для формы обратной связи или мобильного приложения, их нужно исключить отдельно, а не закрывать всё подряд.

Вариант 2. Оставить открытыми только нужные маршруты

Если сайт использует несколько публичных REST-эндпоинтов, лучше не блокировать весь API, а разрешить только конкретные маршруты. Это уже более точная настройка, но и ответственность выше: список нужно поддерживать.

<?php
add_filter( 'rest_authentication_errors', function ( $result ) {
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    if ( is_user_logged_in() ) {
        return $result;
    }

    $uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';

    $allowed = array(
        '/wp-json/my-plugin/v1/public-form',
        '/wp-json/my-plugin/v1/status',
    );

    foreach ( $allowed as $path ) {
        if ( strpos( $uri, $path ) !== false ) {
            return $result;
        }
    }

    return new WP_Error( 'rest_forbidden', 'REST API закрыт для гостей.', array( 'status' => 401 ) );
} );

Такой подход удобен, если вы точно знаете, какие маршруты должны быть доступны без логина. Если список плавающий, поддержка быстро станет неудобной.

Вариант 3. Скрыть лишние данные из REST-ответов

Иногда API нужен, но не хочется отдавать лишнее. Например, можно убрать из REST-ответов поля, которые не нужны фронтенду или внешним сервисам. Это не замена защите, но полезное дополнение.

<?php
add_filter( 'rest_prepare_user', function ( $response, $user, $request ) {
    if ( ! current_user_can( 'list_users' ) ) {
        $data = $response->get_data();
        unset( $data['email'] );
        unset( $data['link'] );
        $response->set_data( $data );
    }

    return $response;
}, 10, 3 );

Этот пример не закрывает API, а лишь уменьшает объём данных. Он полезен, если вам важно не показывать лишнее в ответах, но не решает задачу ограничения доступа.

Пошаговая настройка без поломки сайта

  1. Проверьте, использует ли сайт REST API в админке, редакторе и на фронтенде.
  2. Сделайте резервную копию файлов и базы.
  3. Добавьте код в mu-plugin или дочернюю тему, а не в основную тему, если есть риск обновлений.
  4. Сначала включите ограничение только для гостей.
  5. Проверьте вход в админку, сохранение записей, работу форм и внешних интеграций.
  6. Если нужен публичный маршрут, добавьте его в список исключений.

Если вы предпочитаете плагин вместо кода, выбирайте тот, который позволяет точечно управлять REST-доступом, а не просто «выключает всё». Но даже в этом случае проверьте, не конфликтует ли он с редактором блоков и плагинами, которые используют API для AJAX-подобных запросов.

Как проверить, что ограничение работает

После внедрения важно проверить не только код ответа, но и реальные сценарии. Минимальный чек:

  • открыть /wp-json/ в режиме инкогнито;
  • проверить, что гостевой запрос получает 401 или 403, если это было задумано;
  • авторизоваться в админке и убедиться, что редактор записей работает;
  • сохранить запись, страницу и настройки плагинов, которые завязаны на REST;
  • проверить фронтенд-формы и интеграции, если они есть;
  • посмотреть логи сервера: лишние запросы к API должны исчезнуть или стать заметно реже.

Для быстрой проверки ответа удобно использовать curl:

curl -I https://example.com/wp-json/wp/v2/posts

Если вы закрывали API для гостей, неавторизованный запрос должен возвращать не 200. Если всё ещё приходит 200, значит правило не сработало или его перебивает другой плагин/серверная настройка.

Частые ошибки и как их исправить

Полностью отключили REST API

Это самая частая ошибка. После такого ломаются блоковый редактор, часть плагинов и иногда даже элементы админки. Исправление простое: не отключайте API целиком, а ограничьте только неавторизованные запросы или только конкретные маршруты.

Добавили код в активную тему

После обновления темы ограничение исчезает. Для технических правил лучше использовать mu-plugin или дочернюю тему. Так настройка не потеряется при обновлении.

Не учли публичные маршруты

Если у вас есть формы, интеграции или внешние сервисы, они могут обращаться к REST без логина. Перед блокировкой составьте список реально используемых маршрутов. Иначе получите «случайную» поломку, которую сложно связать с изменением.

Смотрят только на код ответа

Иногда запрос действительно блокируется, но сайт продолжает работать нестабильно из-за кеша, старых правил безопасности или конфликтующего плагина. Проверяйте не только ответ API, но и поведение редактора, форм и авторизованных пользователей.

Безопасность и производительность: что ещё имеет смысл сделать

Если цель — уменьшить поверхность атаки и шум, ограничение REST API лучше сочетать с другими мерами:

  • убрать лишние публичные данные из профилей авторов и записей;
  • проверить, не торчит ли в API чувствительная мета-информация от плагинов;
  • не держать на сайте старые плагины, которые регистрируют открытые маршруты без необходимости;
  • следить за логами 404 и 401 на /wp-json/ — это помогает увидеть сканирование и перебор;
  • если используете кеширование, убедиться, что оно не кэширует ответы, зависящие от авторизации.

Если нужна более широкая чистка технических дублей и служебного мусора, иногда удобнее закрывать не только REST, но и другие лишние точки входа через один аккуратный набор правил. В таких задачах полезны плагины уровня Clearfy Pro, если вам нужен именно набор технических настроек, а не один точечный фильтр.

Главная мысль простая: REST API в WordPress не нужно ломать ради безопасности. Его нужно сузить до того уровня, который реально нужен вашему сайту. Тогда вы убираете лишний доступ, но не создаёте себе новые проблемы в админке и интеграциях.

⭐⭐⭐⭐⭐