Перевод WordPress nonces

WordPress Nonces

Обновленная и расширенная статья опубликована на WP Magazine.

Перевод англоязычной страницы WordPress Nonces на русский из кодекса WordPress. Много информации, технических данных и странных слов.

Nonce расшифровывается как «число, используемое один раз» (number used once) и используются для защиты URL-адресов и форм от некоторых типов неправомерного и злоумышленного использования. Nonce состоит из цифр и букв, имеют ограниченное «время жизни», после которого становятся недействительны. Генерируется Nonce для конкретного пользователя в заданном контексте. Nonce для заданного действия будет неизменной для пользователя до тех пор, пока жизненный цикл не будет закончен.

Токены безопасности в WordPress называются «одноразовыми», несмотря на различия от действительно одноразовых токенов, потому что они предназначены для тех же целей. Они помогают защититься от некоторых типов атак, включая межсайтовую подделку запросов (CSRF), но не защищают от атак повторного воспроизведения (replay atack), потому что Nonce не проверяются на использование лишь единожды.

В качестве примера того, как Nonce используется, рассмотрим некую административную страницу, на которой отображается ссылка для удаления записи с идентификатором 123. Можно заметить, что Nonce содержится в конце адреса:

http://example.com/wp-admin/post.php?post=123&action=trash&_wpnonce=b192fc4204

Если кто-нибудь попытается изменить адрес, чтобы удалить запись с идентификатором 456, то Nonce будет недействительна и попытка удалить другую запись не увенчается успехом.

http://example.com/wp-admin/post.php?post=456&action=trash&_wpnonce=b192fc4204

Неверная Nonce заставит WordPress отдать браузеру ответ «403 Forbidden» с сообщением об ошибке «Вы уверены, что хотите сделать это?».

Nonce в действии. Скриншот исходного кода административной страницы WordPress.

Nonce в действии. Скриншот исходного кода административной страницы WordPress.

Создание Nonce

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

Nonce, используемые в AJAX-запросах, обычно добавляются в скрытые поля формы, откуда к ним может получить доступ Java Script.

Стоит заметить, что Nonce уникальна для текущей сессии пользователя, поэтому, если пользователь входит или выходит асинхронно, Nonce на странице не будут действительными.

Добавление Nonce в качестве аргумента URL

Для того, чтобы добавить Nonce к URL воспользуйтесь фкнцией wp_nonce_url(), указав URL и строчку, обозначающую некое действие. Например:

$complete_url = wp_nonce_url( $bare_url, 'trash-post_'.$post->ID );

Для максимальной безопасности, убедитесь, что строка, описывающая действие, названа максимально конкретно. В примере выше название действия будет выглядеть, как trash-post_123.

По умолчанию, wp_nonce_url() добавляет в адрес аргумент с именем _wpnonce. Но, можно указать другое название при вызове функции, передав третий аргумент, например:

$complete_url = wp_nonce_url( $bare_url, 'trash-post_'.$post->ID, 'my_nonce' );

Добавление Nonce в форму

Для добавления Nonce внутри формы используется функция wp_nonce_field(). В качестве аргумента, как и в случае с добавлением Nonce в адрес, необходимо передать строчку, которая описывает совершаемое действие. По умолчанию, функция выведет два скрытых поля. Первое содержит саму Nonce. Внутри второго — текущий URL (referrer). Например, при таком вызове:

wp_nonce_field( 'delete-comment_'.$comment_id );

Выведется что-то вроде этого:

<input type="hidden" id="_wpnonce" name="_wpnonce" value="796c7766b1" />
<input type="hidden" name="_wp_http_referer" value="/wp-admin/edit-comments.php" />

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

Также можно задать другое имя для поля с Nonce, не выводить поле с referrer и указать, что результат необходимо вернуть, а не выводить. Для подробностей использования смотрите страницу описания функции wp_nonce_field() в Кодексе.

Создание Nonce для других видов использования

Для создания Nonce при использовании в других случаях используйте wp_create_nonce(), передав в качестве аргумента строчку, описывающую действие. Например:

$nonce = wp_create_nonce( 'my-action_'.$post->ID );

После этого, в переменной $nonce окажется уникальный «ключ», например, 295a686963.

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

Проверка действительности Nonce

Вы можете проверить действительность Nonce переданной через URL или внутри формы, или AJAX-запросом, или каким-то другим способом.

Проверка Nonce, полученной с административной страницы

Для проверки Nonce, переданной через URL или внутри формы, необходимо вызвать check_admin_referer(), передав в качестве аргумента строчку, описывающую название действия. Например:

check_admin_referer( 'delete-comment_'.$comment_id );

Функция проверит Nonce и Referrer и, если проверка не будет успешной, то произойдет обычное действие (прекращение выполнения кода с ответом 403 и сообщением об ошибке).

Если вы используете название поля для Nonce отличное от того, что задается по умолчанию (_wpnonce), необходимо указать его во втором аргументе:

check_admin_referer( 'delete-comment_'.$comment_id, 'my_nonce' );

Проверка Nonce, полученной через AJAX-запрос

Для проверки Nonce, полученной через AJAX-запрос, используется check_ajax_referer(). В качестве аргумента необходимо передать название действия:

check_ajax_referer( 'process-comment' );

Функция проверит Nonce (но не Referrer) и в случае, если проверка не будет успешной, завершит исполнение кода.

Если вы используете название поля для Nonce, отличное от того, что задается по умолчанию (_wpnonce или _ajax_nonce), необходимо передать дополнительные параметры. Подробности на странице функции check_ajax_referer() в Кодексе.

Проверка Nonce, полученной другими способами

Для проверки Nonce, полученной другими способами воспользуйтесь функцией wp_verify_nonce(), указав значение полученной Nonce и название действия:

wp_verify_nonce( $_REQUEST['my_nonce'], 'process-comment'.$comment_id );

В случае отрицательного результата не следует продолжать обработку запроса. Обычно, в таких случаях вызывается wp_nonce_ays(), которая отдает браузеру «403 Forbidden» с сообщением «Вы действительно уверены, что хотите сделать это?»

Изменение системы Nonce

Систему работы с Nonce можно изменять, используя различные экшены и фильтры.

Изменение продолжительности жизни Nonce

По умолчанию, срок действия Nonce равен одному дню. После этого Nonce перестает быть действительной даже если название действия совпадает. Для изменения времени используйте фильтр nonce_life, указав необходимое время в секундах. Например, код ниже устанавливает срок действия на 4 часа:

add_filter( 'nonce_life', function () { return 4 * HOUR_IN_SECONDS; } );

Обратите внимание, что Nonce, как говорилось выше, это не «номер, используемый единожды». Срок действия Nonce не совпадает со сроком действия настоящих Nonce. WordPress использует систему с двумя «тиками», где 1 тик равносилен половине продолжительности жизни. Во время второго тика Nonce может быть обновлена, например, через автосохранение. Таким образом, при настройках по умолчанию, где продолжительность действия Nonce составляет 24 часа, это означает, что информация о времени внутри Nonce, говорит сколько двенадцатичасовых периодов времени прошло с начала эпохи Unix. Nonce, созданная в промежуток с 12:00 до 24:00 будет действительна до 12:00 следующего дня. Фактический срок службы составит значение между 12 и 24 часами. Пример выше, где срок службы устанавливался на 4 часа, означает, что Nonce будет действительна от 2 до 4 часов.

Выполнение дополнительных проверок

Для выполнения дополнительных проверок в момент, когда функция check_admin_referer() установила, что Nonce и Referrer являются действительными, можно использовать check_admin_referer в качестве экшена:

function my_additional_check ( $action, $result ) { ... }
add_action( 'check_admin_referrer', 'my_additional_check', 10, 2 );

Аналогичным способом можно «прицепиться» к check_ajax_referer внутри вызова check_ajax_referer().

Изменение сообщения об ошибке

Сообщение с ошибкой, отдаваемое в случае недействительности Nonce, можно заменить на свое, используя фильтр gettext:

function my_nonce_message ($translation) {
  if ($translation == 'Are you sure you want to do this?')
    return 'No! No! No!';
  else
    return $translation;
}
add_filter('gettext', 'my_nonce_message');

От переводчика. Стоит заметить, что функция my_nonce_message() в качестве первого аргумента получит уже переведенный текст. Другими словами, если вы используете не английскую локаль, то будет всегда выполняться блок с else, при условии, что перевод на текущей локали есть :). Чтобы этого избежать, необходимо изменить добавление фильтра, указав, что ваша функция принимает 2 аргумента.

add_filter('gettext', 'my_nonce_message', 10, 2);
  1. Уже переведенный текст.
  2. Оригинальный текст (на английском).

Дополнительные сведения

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

Срок действия Nonce

Продолжительность жизни Nonce разделена на два тика. Пока Nonce действительна, функция wp_verify_nonce(), которая проверяет Nonce, возвращает номер текущего тика — 1 или 2. Эти значения можно использовать, чтобы обновлять Nonce во время второго тика, благодаря чему срок службы не будет прерван.

Nonce и безопасность

Генерация Nonce происходит c использованием ключа и соли, уникальных для каждого сайта, если конечно WordPress установлен правильно. Константы NONCE_KEY и NONCE_SALT объявляются в файле wp-config.php.

Замена системы для работы с Nonce

Некоторые функции для работы с Nonce размещены в файле pluggable.php, что означает, что они могут быть легко заменены своими собственными. Например, для изменения логики проверки АJAX-запросов, необходимо написать свою собственную функцию check_ajax_referrer(). Для замены системы создания, проверки и тиков задекларируйте свои собственные wp_create_nonce(), wp_verify_nonce() и wp_nonce_tick(). Список функций и хуков для работы с Nonce можно найти в разделе Related на страницах англоязычного Кодекса.

При подготовке иллюстрации для статьи использовался фрагмент изображения Криса Харрисона.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s