☰
WEB SECURITY / PRACTICE

Как защитить WordPress REST API от утечки данных

Как защитить WordPress REST API от утечки данных

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

Риск возникает, когда открытые endpoints возвращают больше данных, чем необходимо для работы сайта. Например, маршрут /wp-json/wp/v2/users может помочь собрать идентификаторы, имена и slug авторов. Это не готовый взлом, но такая информация упрощает подготовку атак на учетные записи. Защита должна заключаться не в механической блокировке всего API, а в контроле конкретных маршрутов, ролей и полей ответа.

Что такое REST API и где возникает риск

REST API — это набор HTTP-маршрутов, через которые WordPress принимает или возвращает данные в формате JSON. Базовый адрес обычно выглядит как /wp-json/, а стандартные маршруты для записей и пользователей находятся в пространстве /wp/v2/.

Некоторые endpoint-ы действительно должны быть доступны без авторизации. Например, фронтенд может получать опубликованные записи или страницы. Однако публичный маршрут не должен возвращать черновики, приватные записи, служебные метаполя, адреса электронной почты, токены или данные, которые не нужны посетителю.

Наиболее распространенные проблемы связаны с тремя сценариями: стандартный маршрут раскрывает лишние сведения, кастомный маршрут зарегистрирован без permission_callback или endpoint возвращает приватные данные из-за ошибки при проверке capability.

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

Начните с аудита открытых endpoint-ов

Проверку следует выполнять в двух режимах: как гость и как обычный авторизованный пользователь без административных прав. Администратор часто видит больше в соответствии с правилами WordPress, поэтому его сессия не показывает реальный уровень доступа для других пользователей.

Сначала откройте в браузере или проверьте с помощью инструмента командной строки адрес /wp-json/. Он возвращает список доступных пространств и маршрутов. Затем проверьте только те endpoint-ы, которые реально использует сайт: записи, страницы, медиафайлы, пользователей, кастомные типы записей и маршруты плагинов.

Для автоматизированной проверки можно использовать curl. Запрос без cookies показывает, что доступно обычному посетителю:

  • проверьте /wp-json/wp/v2/users и варианты маршрута с конкретным ID;
  • проверьте /wp-json/wp/v2/posts, pages и зарегистрированные кастомные post types;
  • попробуйте параметры per_page, search, author, include и _embed;
  • сравните ответы гостя, обычного пользователя и администратора;
  • проверьте HTTP-код, структуру JSON и поля, которые не нужны фронтенду.
curl -i 'https://example.com/wp-json/wp/v2/users?per_page=10'

curl -i 'https://example.com/wp-json/wp/v2/posts?per_page=5&_embed'

На что смотреть в ответе

Само наличие ID или имени автора не всегда означает утечку критически важных данных: эти поля могут требоваться для отображения авторства. Важно оценивать контекст. Если endpoint позволяет перебирать пользователей, раскрывает служебные поля или предоставляет доступ к неопубликованному контенту, его необходимо ограничить.

Особенно внимательно проверяйте ответы после установки плагинов, создания кастомных post types и подключения CRM или мобильного приложения. Именно в кастомных маршрутах чаще всего отсутствует корректная проверка доступа.

Как правильно ограничить список пользователей

Публичный список пользователей нужен не каждому сайту. Если авторы не отображаются на фронтенде, маршрут /wp/v2/users можно закрыть для гостей или всех ролей, которым он не требуется. Однако перед блокировкой проверьте Gutenberg, Elementor, поиск авторов и сторонние интеграции.

Более безопасный подход — запрещать доступ пользователям, у которых нет соответствующей capability, а не отключать REST API полностью. Пример ниже блокирует доступ к маршрутам пользователей для тех, у кого нет capability list_users. Добавляйте этот код в небольшой собственный плагин или mu-plugin, а не непосредственно в файл темы.

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

  • не скрывайте только ссылку на endpoint — проверка должна выполняться на сервере;
  • не полагайтесь на параметр _fields как на механизм авторизации;
  • если список необходим, возвращайте только минимальный набор полей, например ID и публичное имя;
  • также проверьте доступ к конкретному пользователю по маршруту /wp/v2/users/{id}.
add_filter('rest_pre_dispatch', function ($result, $server, $request) {
    $route = $request->get_route();

    if (preg_match('#^/wp/v2/users(?:/|$)#', $route)
        && ! current_user_can('list_users')) {
        return new WP_Error(
            'rest_forbidden',
            'Доступ запрещен.',
            ['status' => 403]
        );
    }

    return $result;
}, 10, 3);

Защита кастомных REST-маршрутов

Каждый собственный маршрут должен иметь permission_callback. Этот callback определяет, может ли текущий запрос получить доступ к endpoint-у. Одной проверки is_user_logged_in() недостаточно: у любого авторизованного пользователя может быть меньше прав, чем у администратора или менеджера конкретного процесса.

Для операций чтения используйте capability, соответствующую данным. Для изменения или удаления информации проверяйте права еще строже и дополнительно проверяйте nonce или другой механизм аутентификации — в зависимости от способа работы интеграции.

Публичные маршруты также должны возвращать только необходимые данные. Не передавайте весь объект пользователя или записи, если фронтенду нужны лишь несколько значений.

  • для административных данных используйте current_user_can('manage_options') или более точную capability;
  • при доступе к конкретной записи проверяйте не только роль, но и статус, автора и правила доступа;
  • для кастомных post types устанавливайте show_in_rest только тогда, когда REST-доступ действительно необходим;
  • валидируйте и очищайте параметры запроса, особенно ID, поисковые строки и значения фильтров.
register_rest_route('site/v1', '/reports', [
    'methods'  => WP_REST_Server::READABLE,
    'callback' => 'site_get_reports',
    'permission_callback' => function () {
        return current_user_can('manage_options');
    },
]);

Не допускайте утечки метаданных и приватного контента

REST API может возвращать не только заголовок и текст записи. В ответе могут присутствовать author, featured_media, навигационные ссылки, встроенные объекты и зарегистрированные метаполя. Если метаполе зарегистрировано с show_in_rest, оно потенциально становится доступным через API в соответствии с правилами его авторизации.

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

Параметр _fields может уменьшить объем ответа и скрыть ненужные поля от конкретного клиента, но он не заменяет permission_callback. Пользователь может изменить параметры запроса, поэтому право доступа должно проверяться до формирования ответа.

  • проверьте, доступны ли черновики, запланированные и приватные записи;
  • изучите регистрацию метаполей и их функцию auth_callback;
  • не возвращайте адреса электронной почты и другие персональные данные без четкой функциональной необходимости;
  • ограничьте _embed, если встроенные объекты раскрывают лишние сведения;
  • убедитесь, что ошибки API не содержат SQL-запросов, путей к файлам или служебной диагностики.

Аутентификация, nonce и CORS

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

Для внешних интеграций используйте отдельную схему аутентификации с минимальными правами. Не передавайте административные cookies или пароли в JavaScript на фронтенде. Application Passwords и другие учетные данные необходимо хранить на сервере интеграции, а не в коде страницы.

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

  • разрешайте CORS только для конкретных доверенных доменов, если он действительно необходим;
  • не используйте wildcard для приватных ответов с cookies или авторизацией;
  • отзывайте ключи интеграций, которые больше не используются;
  • разделяйте публичные маршруты и маршруты для внутренних сервисов.

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

Защиту REST API нельзя считать завершенной после добавления одного правила. Необходима повторная проверка ролей и сценариев, зависящих от API. Гость должен получать только публичные данные, обычный пользователь — только разрешенные ресурсы, а запрещенные действия должны возвращать 401 или 403, а не полный JSON с данными.

Отдельно проверьте Gutenberg, Elementor, формы, поиск, фильтры, медиабиблиотеку, блоки авторов и подключенные сервисы. Если после ограничения доступа редактор перестал работать, не открывайте весь API без ограничений. Определите конкретный маршрут, выясните необходимую capability и разрешите только нужный сценарий.

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

  • очистите кеш после изменений и проверьте API без старых cookies;
  • протестируйте запросы с разными ролями, а не только с учетной записью администратора;
  • проверьте журнал ошибок и логи веб-сервера на необычные обращения к API;
  • обновляйте WordPress, плагины и тему, поскольку ошибки контроля доступа часто исправляются в обновлениях;
  • не скрывайте endpoint через robots.txt: это не ограничивает технический доступ.

Частые вопросы

Нужно ли полностью отключать WordPress REST API?

Обычно нет. Полное отключение может нарушить работу Gutenberg, Elementor, мобильных приложений и интеграций. Лучше ограничить конкретные маршруты, записи, метаполя и операции, которые не нужны сайту.

Является ли доступ к /wp-json/wp/v2/users критической уязвимостью?

Сам по себе этот маршрут не означает взлом. Однако он может раскрывать публичные идентификаторы и упрощать подготовку атак. Если список пользователей не нужен, его стоит закрыть для гостей или пользователей без соответствующей capability.

Защитит ли nonce от утечки данных через REST API?

Нет. Nonce помогает подтвердить запрос в определенном сценарии аутентификации, но не заменяет проверку прав и не скрывает данные публичного endpoint-а.

Можно ли скрыть лишние поля с помощью параметра _fields?

Параметр _fields полезен для уменьшения ответа, но не является механизмом безопасности. Пользователь может изменить запрос, поэтому конфиденциальные поля нужно защищать при формировании ответа и с помощью проверки прав.

Что делать, если после ограничения API перестал работать Elementor?

Проверьте запросы редактора в инструментах разработчика браузера, определите конкретный маршрут и нужную роль. Откройте только этот endpoint с корректным permission_callback, а не весь REST API.

Вывод

Защита WordPress REST API начинается с инвентаризации маршрутов и проверки ответов для разных ролей. Закройте ненужный доступ к пользователям, приватным записям и метаданным, добавьте permission_callback к кастомным endpoint-ам и возвращайте только минимально необходимые поля.

Не отключайте REST API без разбора. Сочетание точных проверок capability, безопасной аутентификации, ограниченного CORS и регулярного тестирования позволяет уменьшить утечку данных без ущерба для Gutenberg, Elementor и рабочих интеграций.

← Все материалы веб-безопасности