wordpressa.ru wordpress wordpressa.ru

Как исправить 403 и 401 при запросах к WordPress REST API

Если внешний сервис, кастомная тема или плагин внезапно перестали получать данные из REST API WordPress, чаще всего проблема не в самом API, а в авторизации, кэше, защите на сервере или в плагине безопасности. Ошибка может выглядеть как 401 Unauthorized, 403 Forbidden или даже как пустой ответ, если запрос режется до PHP.

Ниже — практический разбор: как быстро локализовать источник блокировки, что менять в настройках и коде, и как проверить, что после правки API действительно работает, а не просто “ошибка исчезла в админке”.

Когда проблема точно в REST API, а не в теме или JS

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

Типичные симптомы

  • в консоли браузера запрос к /wp-json/wp/v2/posts возвращает 401 или 403;
  • внешний сервис не может получить данные по Basic Auth, Application Passwords или OAuth-обвязке;
  • после установки плагина безопасности перестали работать AJAX-формы и headless-интеграции;
  • на одном хостинге API работает, на другом — нет, хотя код одинаковый;
  • запросы проходят в админке, но падают с фронтенда из-за отсутствия nonce.

Что проверить первым делом

  1. Откройте /wp-json/ в браузере без авторизации.
  2. Проверьте конкретный маршрут, например /wp-json/wp/v2/posts?per_page=1.
  3. Посмотрите ответ в DevTools: статус, заголовки, тело ошибки.
  4. Временно отключите плагины безопасности и кэширования на тестовой копии сайта.
  5. Проверьте, не режет ли запрос серверный WAF, ModSecurity или Cloudflare.

Почему WordPress REST API отвечает 401 или 403

У этих статусов разные причины, и лечатся они по-разному. 401 обычно означает, что запрос не авторизован или авторизация не дошла до WordPress. 403 чаще связан с запретом доступа: по правам пользователя, nonce, правилам безопасности или серверной фильтрации.

СценарийЧто видитеЧто обычно делать
Нет авторизации401 UnauthorizedПроверить заголовок Authorization, Application Passwords, cookies и nonce
Плагин безопасности403 ForbiddenНайти правило блокировки, добавить исключение для маршрута
Серверный WAF403 или пустой ответСмотреть логи ModSecurity/Cloudflare, менять правило на стороне хостинга
Неверный capability401/403 на кастомном endpointИсправить callback проверки прав в permission_callback

Пошаговое решение: от проверки заголовков до прав доступа

1. Проверьте, доходит ли заголовок Authorization

Если вы используете Application Passwords или внешнюю авторизацию, сервер должен передавать заголовок Authorization в PHP. На части конфигураций Nginx/Apache он теряется, и WordPress видит запрос как анонимный.

// functions.php или mu-plugin: диагностический лог для REST-запросов
add_action('rest_api_init', function () {
    if (defined('WP_DEBUG') && WP_DEBUG) {
        error_log('REST Authorization: ' . (isset($_SERVER['HTTP_AUTHORIZATION']) ? 'present' : 'missing'));
    }
});

Если в логе заголовка нет, сначала чините серверную конфигурацию. На Nginx часто нужно явно пробросить заголовок в PHP-FPM. На Apache проблема может быть в правилах прокси или модуле авторизации.

2. Убедитесь, что endpoint не требует лишних прав

Для кастомных маршрутов в register_rest_route() часто ставят слишком строгий permission_callback. В результате запросы от фронтенда или внешнего сервиса получают 403, хотя данные не секретные.

add_action('rest_api_init', function () {
    register_rest_route('site/v1', '/public-data', [
        'methods'  => 'GET',
        'callback' => function () {
            return [
                'status' => 'ok',
                'time'   => current_time('mysql'),
            ];
        },
        'permission_callback' => '__return_true',
    ]);
});

Если данные публичные, не проверяйте там current_user_can() без необходимости. Если данные приватные, проверяйте конкретную capability, а не просто факт входа в систему.

3. Проверьте nonce для запросов из админки

Для запросов из wp-admin и некоторых фронтенд-скриптов WordPress ожидает nonce. Если тема или плагин отправляет устаревший nonce, API вернёт 403 с сообщением о проверке безопасности.

wp_localize_script('my-admin-script', 'MyApi', [
    'root'  => esc_url_raw(rest_url()),
    'nonce' => wp_create_nonce('wp_rest'),
]);

На стороне JavaScript заголовок должен уходить в запросе:

fetch(MyApi.root + 'wp/v2/posts?per_page=1', {
    method: 'GET',
    headers: {
        'X-WP-Nonce': MyApi.nonce
    },
    credentials: 'same-origin'
});

Если nonce создаётся правильно, но запрос всё равно падает, проверьте, не кэшируется ли HTML-страница с устаревшим токеном.

4. Исключите плагины безопасности и кэш

Частая история: REST API блокирует не WordPress, а плагин, который считает запрос подозрительным. Это особенно заметно, если на сайте включены ограничения по /wp-json/, защита от брутфорса, скрытие версии или фильтрация заголовков.

На тестовой копии отключайте плагины по одному и повторяйте запрос. Если проблема исчезает после деактивации конкретного плагина, ищите в его настройках исключение для REST API или whitelist для маршрута.

  • проверьте правила, связанные с wp-json;
  • посмотрите, не блокируется ли Authorization;
  • отключите агрессивный кэш для страниц, где формируется nonce;
  • убедитесь, что CDN не кэширует ответ API как статический.

Если ошибка появляется только на кастомном endpoint

Тогда проблема почти всегда в коде маршрута. WordPress не даст выполнить callback, если permission_callback возвращает false или если в нём есть ошибка. Иногда разработчик случайно использует is_user_logged_in() там, где нужен более точный контроль прав.

Ниже пример безопасной проверки доступа для endpoint, который должен быть доступен только редакторам и администраторам:

add_action('rest_api_init', function () {
    register_rest_route('site/v1', '/reports', [
        'methods'  => 'GET',
        'callback' => 'site_get_reports',
        'permission_callback' => function () {
            return current_user_can('edit_others_posts');
        },
    ]);
});

function site_get_reports(WP_REST_Request $request) {
    return rest_ensure_response([
        'items' => [],
    ]);
}

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

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

После правок важно не ограничиваться открытием страницы в браузере. REST API нужно проверять тем же способом, которым его использует реальный клиент: из консоли, из curl или из приложения.

Проверка через curl

curl -i https://example.com/wp-json/wp/v2/posts?per_page=1

Если запрос авторизованный, добавьте заголовки, которые использует ваш сценарий:

curl -i \
  -H 'Authorization: Basic base64loginpassword' \
  -H 'X-WP-Nonce: your-nonce' \
  https://example.com/wp-json/wp/v2/users/me

Смотрите не только на код ответа, но и на тело. WordPress обычно возвращает полезное сообщение, по которому можно понять, что именно сломано: nonce, права, маршрут или авторизация.

Проверка в браузере

  • ответ 200 на нужный маршрут;
  • нет редиректа на страницу логина;
  • нет сообщений о невалидном nonce;
  • в DevTools виден корректный заголовок Authorization или X-WP-Nonce;
  • данные приходят именно с того сайта, а не из старого кэша CDN.

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

Ставят __return_true на приватный endpoint

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

Проверяют только is_user_logged_in()

Пользователь может быть залогинен, но не иметь нужных прав. Для REST API лучше проверять конкретную capability, например edit_posts, manage_options или более узкую, если она есть в вашей роли.

Не учитывают кэш страницы с nonce

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

Блокируют API на уровне WAF

Иногда хостинг или CDN режет запросы к /wp-json/ по сигнатурам. В WordPress это выглядит как “непонятный 403”, но в логах сервера видно конкретное правило. Без логов здесь легко потратить время на правку PHP, хотя проблема находится выше.

Практика: как не сломать безопасность и производительность

Открывать REST API шире, чем нужно, не стоит. Но и закрывать всё подряд — плохая идея: ломаются редактор, мобильные клиенты, интеграции и собственные скрипты. Рабочий подход — минимально необходимый доступ и точечные исключения.

  • не отключайте REST API целиком, если не понимаете, какие части сайта его используют;
  • для публичных данных делайте отдельный маршрут с понятным permission_callback;
  • для приватных данных проверяйте capability, а не только факт авторизации;
  • не кэшируйте ответы, которые зависят от пользователя;
  • проверяйте логи сервера до правки PHP, если ошибка возникает только на проде.

Если на сайте уже есть плагин для SEO и чистки дублей, например Clearfy Pro, его настройки стоит проверять отдельно: иногда именно там включены ограничения, которые затрагивают wp-json или заголовки авторизации. Но любые такие изменения лучше тестировать на staging, а не на живом сайте.

Когда REST API снова отвечает стабильно, у вас должны совпасть три вещи: запрос проходит без ручных обходов, права доступа соответствуют задаче, а кэш и защита не ломают легитимные обращения. Если хотя бы один из этих пунктов не выполнен, ошибка вернётся при следующем обновлении плагина, темы или конфигурации сервера.

×

AI-плагин

WPGPT
Сам создает статьи для вашего сайта WordPress

SEO и мета-теги

Парсинг конкурентов

Изображения

Комментарии

Подробнее