REST API в WordPress (о котором мы рассказывали в предыдущей статье) сочетает в себе два типа эндпоинтов: одни доступны для чтения любому пользователю без авторизации, другие же полностью блокируют доступ, если вы не вошли в систему. Внутри wp-admin браузер незаметно отправляет запросы к этому же API на протяжении всего времени, пока вы редактируете контент — и при этом вам не приходится заново вводить пароль для каждого действия. В этой статье мы разберем механизм, который за этим стоит: аутентификацию через cookie+nonce, а также отдельный механизм, созданный для других целей — пароли приложений (Application Passwords).
Что аутентифицирует запрос внутри wp-admin
Когда вы входите в WordPress, ваш браузер получает аутентификационную куку с именем wordpress_logged_in_* . С этого момента каждый запрос, отправляемый браузером на этот домен, автоматически содержит эту куку, поэтому сервер может определить, «кто вошел в систему», просто проверив ее. Когда собственный JavaScript-код в wp-admin обращается к REST API — например, при автосохранении черновика или когда редактор блоков обновляет запись в фоновом режиме — он использует эту же куку.
Примечание: CSRF (Cross-Site Request Forgery, межсайтовая подделка запроса) — это атака, при которой, пока вы авторизованы на сайте, вредоносная страница, которую вы случайно открыли, инициирует запросы к этому сайту с использованием кук вашего браузера без вашего ведома — например, удаляя запись или изменяя настройки. Поскольку браузеры прикрепляют куки автоматически, сама по себе кука не может служить доказательством того, что запрос был отправлен вами намеренно.
Именно эту уязвимость и использует CSRF. Поскольку куки отправляются автоматически, посещение вредоносной страницы в авторизованном состоянии приведет к отправке той же куки. Если бы REST API принимал запросы на запись только на основе проверки кук, простая загрузка вредоносной страницы авторизованным пользователем могла бы привести к нежелательному удалению записи или изменению настроек аккаунта.
Для чего нужен nonce
Nonce (одноразовый код) закрывает эту уязвимость. Вопреки названию, предполагающему однократное использование («used once»), nonce в WordPress на самом деле представляет собой токен, привязанный к текущей сессии авторизации, валидный в течение определенного времени (по умолчанию 24 часа, с возможностью продления примерно до 48 часов за счет ротации) и ограниченный конкретным действием. Сервер генерирует его с помощью wp_create_nonce('some-action-name') и внедряет в HTML/JS страницы wp-admin. Запросы на запись в REST API должны содержать это значение в заголовке X-WP-Nonce , а сервер проверяет его для авторизованного пользователя с помощью wp_verify_nonce() .
Вредоносный внешний сайт никак не может получить это значение nonce — оно внедряется только в саму страницу wp-admin, которая находится на том же источнике (same origin). Поэтому, даже если странице злоумышленника удастся использовать вашу куку, проверка nonce все равно заблокирует запрос. Проще говоря: кука отвечает на вопрос «кто это», а nonce — «действительно ли этот пользователь намеревался совершить это действие с этой страницы прямо сейчас». Для успешного выполнения REST-запроса из wp-admin должны пройти проверку оба фактора.
Где связка cookie+nonce не работает
Вся эта схема предполагает, что запросы исходят из того же браузера в рамках той же сессии wp-admin. Обратная сторона заключается в том, что это плохо работает для программ, которые вообще не используют браузер — например, для консольной утилиты или скрипта на другом сервере, которым нужно напрямую вызвать REST API. Куки привязаны к сессии входа в браузер, и у внешней программы нет простого способа получить или поддерживать их; nonce аналогично недолговечны, и их нужно запрашивать заново при каждой загрузке страницы wp-admin.
Пароли приложений (Application Passwords): альтернативный вход
Пароли приложений (Application Passwords), появившиеся в ядре WordPress начиная с версии 5.6 (2020 год), решают именно эту задачу — безопасный вызов REST API внешними программами — с помощью механизма, полностью отделенного от cookie+nonce. Под капотом это напоминает HTTP Basic-аутентификацию. На странице своего профиля в wp-admin пользователь может сгенерировать новый пароль приложения, указав имя программы, для которой он предназначен. В результате создается случайно сгенерированный пароль, отличный от основного пароля для входа; отправляемый в заголовке Authorization: Basic , он дает те же права доступа, что и сама учетная запись.
Ключевых отличий от cookie+nonce два. Во-первых, этот способ не зависит от состояния сессии браузера — как только у вас есть пароль, любая программа может сразу его использовать. Во-вторых, каждый такой пароль можно отозвать индивидуально. Нет необходимости передавать свой реальный пароль для входа внешней интеграции; если вы решите прекратить ее использование, вы просто отзываете этот конкретный пароль приложения в wp-admin, не меняя свои основные учетные данные и не затрагивая другие подключенные инструменты.
Реальный случай, когда аутентификация вообще не требуется
Интересно, что раздел «Из блога» на нашем собственном лендинге ( en.wpmm.jp/ ), созданный с помощью скрипта blog_latest.php (о котором шла речь в предыдущей статье), не использует ни один из этих механизмов. Он вызывает только /wp/v2/posts — эндпоинт только для чтения опубликованных записей, который изначально спроектирован так, чтобы быть доступным любому пользователю без аутентификации. Аутентификация в REST API становится необходимой только тогда, когда вы выходите за рамки публичных данных — запрашиваете черновики, создаете или обновляете записи, меняете настройки. Разделение на три уровня — читать может каждый, писать может только авторизованный пользователь, а внешняя программа пишет через выделенный пароль приложения — позволяет легко решить, какой подход к аутентификации действительно нужен для конкретной задачи.
Резюме
Запросы внутри wp-admin сочетают в себе две проверки — куку (кто вошел в систему) и nonce (намеревался ли этот человек совершить это действие с этой страницы прямо сейчас), чтобы блокировать CSRF, избавляя вас от необходимости повторно вводить пароль при каждом запросе. Но поскольку эта схема сильно опирается на состояние сессии браузера, она не подходит для внешних программ, вызывающих REST API. Пароли приложений закрывают этот пробел с помощью отдельного класса токенов, которые можно выпускать и отзывать независимо от основного пароля. Одно и то же понятие «аутентификация в REST API» требует разных механизмов в зависимости от того, отправляется запрос из браузера или извне — об этом стоит помнить каждый раз, когда вы решаете, как именно должен аутентифицироваться ваш код.
Комментарии (0)
Пока нет комментариев — будьте первым.