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-ів справді має бути доступною без авторизації. Наприклад, фронтенд може отримувати опубліковані записи або сторінки. Однак публічний маршрут не повинен повертати чернетки, приватні записи, службові метаполя, email-адреси, токени чи дані, які не потрібні відвідувачу.
Найчастіші проблеми пов’язані з трьома сценаріями: стандартний маршрут розкриває зайві відомості, кастомний маршрут зареєстрований без permission_callback, а endpoint повертає приватні дані через помилку в перевірці capability.
- публічний список користувачів або авторів без функціональної потреби;
- доступ до приватних типів записів, чернеток і внутрішніх таксономій;
- виведення email, телефонів, службових 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;
- не повертайте email та інші персональні дані без чіткої функціональної потреби;
- обмежуйте _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 та робочих інтеграцій.