Після увімкнення page cache у WordPress сайт може почати повертати помилку `403 - Are you sure you want to do this?`. Часто причина не в самому AJAX, формі чи REST API, а в nonce, який був вставлений у HTML сторінки, а потім потрапив у кеш.
Nonce у WordPress — це короткоживучий захисний токен для перевірки наміру користувача. Якщо кеш віддає застарілий або створений в іншому контексті nonce, сервер відхиляє запит. Нижче розберемо, як підтвердити проблему, які варіанти виправлення є безпечними та яких помилок варто уникати.
Що таке nonce у WordPress і для чого він потрібен
WordPress nonce — це не пароль і не повноцінний механізм авторизації. Він допомагає переконатися, що запит надійшов із форми або інтерфейсу, який WordPress вважає допустимим, а не був безпосередньо підроблений стороннім сайтом.
Nonce зазвичай створюють через `wp_create_nonce()`, а перевіряють за допомогою `wp_verify_nonce()`, `check_ajax_referer()` або вбудованої перевірки REST API. Токен пов’язаний із користувацькою сесією та часовим інтервалом. У WordPress nonce зазвичай дійсний обмежений період, який може охоплювати поточний або попередній часовий інтервал, тому його не слід вважати довічним ключем.
Якщо операція змінює дані, nonce має бути лише одним із рівнів захисту. Сервер також повинен перевіряти права користувача через `current_user_can()` або інший відповідний механізм.
- Для AJAX nonce часто передається в POST-параметрі або окремому HTTP-заголовку.
- Для REST API WordPress зазвичай використовують заголовок `X-WP-Nonce`.
- Nonce не замінює перевірку сесії, ролі, capability або санітизацію вхідних даних.
Як кеш сторінки ламає nonce
Проблема виникає, коли HTML із nonce зберігається у page cache, кеші CDN, reverse proxy або кеші плагіна оптимізації. Наступний відвідувач отримує не свіжий HTML, сформований для його запиту, а вже збережену копію сторінки.
Для авторизованого користувача це особливо критично: сторінка може містити nonce, створений для іншої сесії. Навіть якщо візуально сторінка однакова для всіх, токен усередині неї може бути персоналізованим.
Застарілий nonce також з’являється, коли кеш живе довше, ніж період актуальності токена. У такому разі помилка починається не одразу після публікації сторінки, а через певний час.
Типовий симптом — в адміністратора або після очищення кешу все працює, а у звичайного користувача форма чи AJAX-запит завершується помилкою. Після повторного завантаження сторінки результат може тимчасово змінитися, що ускладнює діагностику.
- HTML сторінки кешується разом із прихованим полем nonce.
- CDN віддає стару копію документа з уже неактуальним токеном.
- Кеш може змішувати публічний HTML і персоналізовані дані.
- Очищення лише браузерного кешу не допоможе, якщо стара копія зберігається на сервері або CDN.
Як підтвердити, що причина саме в кешуванні
Почніть із порівняння поведінки сторінки з увімкненим і вимкненим кешем. Якщо після тимчасового обходу page cache запит починає працювати, це сильна ознака конфлікту між кешем і nonce.
Перевірте HTML-код сторінки та знайдіть назву поля або змінну, у якій передається nonce. Потім відкрийте DevTools браузера, перейдіть на вкладку Network і подивіться, яке значення фактично відправляється в AJAX або REST-запиті.
Зверніть увагу на заголовки відповіді HTML. Вони можуть показати, чи була сторінка отримана з кешу: наприклад, через службові заголовки CDN або плагіна. Конкретні назви залежать від інфраструктури, тому не варто орієнтуватися лише на один заголовок.
Для перевірки протестуйте кілька сценаріїв: авторизований користувач, гість, приватне вікно браузера, різні пристрої та повторне відкриття сторінки після завершення терміну кешу. Важливо також перевірити не тільки фронтенд, а й сам серверний обробник.
- Перегляньте вкладку Network і статус AJAX або REST-запиту.
- Перевірте, чи передається `X-WP-Nonce` саме в REST-запиті.
- Тимчасово очистіть page cache, object cache і кеш CDN, якщо він використовується.
- Подивіться логи сервера або журнал WordPress, щоб відрізнити помилку nonce від помилки прав доступу.
- Переконайтеся, що сервер не приймає запит лише на підставі наявності параметра nonce без його перевірки.
Найнадійніші способи виправлення
Вибір рішення залежить від того, чи є сторінка персоналізованою та наскільки важливо кешувати її повністю. Не потрібно вимикати весь кеш сайту через одну форму — зазвичай достатньо розділити публічний контент і динамічні операції.
- Не кешуйте сторінки з персоналізованими формами, кабінетом користувача, кошиком, оформленням замовлення або іншими сесійними даними. Такі сторінки краще виключити з page cache на рівні плагіна, сервера та CDN.
- Отримуйте nonce окремим некешованим AJAX або REST-запитом після завантаження сторінки. У цьому випадку основний HTML залишається швидким і публічним, а токен запитується безпосередньо перед операцією.
- Для endpoint, який повертає nonce або інші персоналізовані дані, використовуйте відповідні заголовки на кшталт `Cache-Control: no-store`. Це має бути налаштовано на сервері або в коді endpoint, а не лише в браузері.
- Розділяйте кешування за cookie або станом авторизації. Авторизовані користувачі не повинні отримувати ту саму кешовану HTML-копію, що й анонімні відвідувачі.
- Для REST-запитів передавайте свіжий токен у `X-WP-Nonce`, а не зберігайте його в довгоживучому кешованому HTML.
Приклад отримання nonce окремим запитом
Схема нижче показує загальний підхід: сторінка може кешуватися, а nonce отримується після її завантаження. Реальний URL і формат відповіді залежать від вашого endpoint.
fetch('/wp-json/my-plugin/v1/nonce', {
method: 'GET',
credentials: 'same-origin',
cache: 'no-store'
})
.then(response => response.json())
.then(data => {
const nonce = data.nonce;
// Використайте nonce у наступному запиті.
});
Передавання nonce у REST-запиті
Для стандартної інтеграції WordPress REST API nonce передають у заголовку `X-WP-Nonce`. Сервер усе одно повинен перевірити автентифікацію, права доступу та вхідні дані.
fetch('/wp-json/my-plugin/v1/item', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': nonce
},
body: JSON.stringify({ title: 'Приклад' })
});
Перевірка серверного коду: nonce не замінює авторизацію
Навіть свіжий nonce не означає, що користувач має право виконувати операцію. Обробник повинен окремо перевіряти capability, наприклад `edit_posts`, `manage_options` або спеціальний дозвіл, який відповідає конкретній дії.
Для AJAX перевіряйте nonce на початку обробника через відповідний WordPress-механізм. Для REST API повертайте помилку, якщо користувач не автентифікований або не має потрібних прав. Після цього санітизуйте та валідуйте всі вхідні значення.
Не намагайтеся вирішити проблему кешу, збільшуючи термін життя nonce або вимикаючи його перевірку. Це може приховати симптом, але послабить захист і не усуне проблему персоналізації HTML.
- Nonce перевіряє актуальність і походження запиту, але не доводить наявність потрібної ролі.
- Операції зміни, видалення чи публікації даних мають перевіряти capability.
- Помилки доступу потрібно логувати так, щоб не записувати самі токени у відкритому вигляді.
- Не передавайте nonce через URL, якщо для цього немає чіткої потреби: URL можуть потрапити в логи, історію та сторонні системи.
if ( ! check_ajax_referer( 'my_action', 'nonce', false ) ) {
wp_send_json_error( 'Недійсний nonce', 403 );
}
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( 'Недостатньо прав', 403 );
}
// Далі: валідація даних і виконання операції.
Поширені помилки під час налаштування кешу
Найчастіша помилка — кешувати всю сторінку без аналізу її вмісту. Публічна стаття або сторінка може безпечно кешуватися, але вставлена в неї форма з nonce робить HTML частково динамічним.
Інша проблема — очищати тільки один рівень кешу. Стара копія може залишитися у плагіні, вебсервері, CDN або браузері. Після зміни правил перевіряйте всі рівні та дочекайтеся оновлення або примусово очистіть відповідний кеш.
Не варто вставляти nonce у JavaScript-файл, який має довгий кешований термін життя. Якщо скрипт містить токен, він фактично стає персоналізованим ресурсом. Краще передавати свіжі значення через некешований endpoint або локалізовані дані з урахуванням правил кешу.
Також небезпечно повертати сторінку з персональними даними під загальним публічним URL. Проблема в такому випадку ширша за nonce: кеш може показати одному користувачу дані іншого.
- Не покладайтеся лише на очищення браузерного кешу.
- Не кешуйте відповіді endpoint, який повертає nonce або дані сесії.
- Не вимикайте перевірку nonce через помилки 403.
- Не використовуйте один статичний токен для всіх користувачів.
- Після змін протестуйте сторінку і як гість, і як авторизований користувач.
Практичний чекліст перед запуском
Перед увімкненням повносторінкового кешу пройдіть усі сценарії, у яких HTML містить nonce або інші сесійні дані. Це допоможе виявити проблему до того, як її помітять користувачі.
- Складіть список сторінок із формами, AJAX-діями, REST-операціями та особистими кабінетами.
- Визначте, які сторінки можна кешувати як публічні, а які потрібно виключити.
- Перевірте, чи не потрапляють nonce у кешований HTML, JavaScript або CDN-відповідь.
- Для динамічних токенів передбачте окремий endpoint із `Cache-Control: no-store`.
- Перевірте заголовок `X-WP-Nonce` у REST-запитах.
- Переконайтеся, що сервер перевіряє capability, сесію, nonce та вхідні дані.
- Протестуйте поведінку після завершення терміну кешу та після примусового очищення всіх рівнів кешування.
Поширені запитання
Чи потрібно повністю вимикати кеш у WordPress, якщо виникла помилка nonce?
Ні. Зазвичай достатньо виключити з page cache персоналізовані сторінки та endpoint, які повертають nonce або сесійні дані. Публічні сторінки без динамічних токенів можна продовжувати кешувати.
Чому nonce працює для адміністратора, але не працює для звичайного користувача?
Адміністратор може отримувати свіжу сторінку без кешу або мати інший cookie-контекст. Звичайний користувач часто отримує загальну кешовану копію HTML із чужим або застарілим nonce.
Чи можна просто збільшити термін дії nonce?
Це не є правильним рішенням. Збільшення терміну може зменшити рівень захисту, але не усуне проблему nonce, який уже збережений у кешованому HTML. Потрібно змінити схему кешування або отримувати токен окремо.
Чи достатньо перевірки nonce для захисту AJAX або REST endpoint?
Ні. На сервері додатково перевіряйте автентифікацію, capability користувача, правильність і допустимість вхідних даних. Nonce не є заміною авторизації.
Де передавати nonce у WordPress REST API?
Для запитів із відповідною сесією WordPress зазвичай використовують HTTP-заголовок `X-WP-Nonce`. Не зберігайте цей токен у довгоживучому кешованому HTML і не вважайте його універсальним API-ключем.
Висновок
Кешування і WordPress nonce добре працюють разом лише тоді, коли публічний контент відокремлений від персоналізованих даних. HTML із сесійним або часовим токеном не можна бездумно роздавати всім відвідувачам із page cache.
Оптимальна схема — кешувати статичний контент, виключити персоналізовані сторінки, отримувати nonce окремим некешованим запитом і перевіряти на сервері не тільки nonce, а й права користувача. Так можна зберегти переваги кешування без помилок 403 та послаблення безпеки.