WordPress Nonces

Nonces (одноразовые числа) – одна из важнейших частей безопасности WordPress. К сожалению, этот инструмент часто неправильно понимают или используют. Одноразовые числа – это инструмент, который позволяет авторизовывать HTTP-запросы к вашему сайту и тем самым обеспечивает безопасность кода.

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

Что такое WordPress Nonce

Nonces – это криптографические хеши, которые используются для того, чтобы проверить, был ли HTTP-запрос сделан уполномоченным на это человеком или клиентом. Поскольку одноразовые числа создаются с применением криптографических алгоритмов хеширования (md5, sha1, sha2 и т.д.) и уникального ключа шифрования, то подделать nonces практически невозможно.

Слово ‘nonce’ означает ‘number used once’ (число, используемое один раз). Одноразовое использование является ключевой особенностью безопасности для nonces. Даже если nonce будет перехвачено, то после его использования один раз оно теряет свою ценность. Это делает одноразовыми числами полезными для отражения повторяющихся атак.

Тем не менее, WordPress Nonces – это не настоящие одноразовые числа. Они могут быть использованы сколько угодно раз в течение 12 часов после их создания, либо в течение другого времени, установленного с помощью фильтра WordPress nonce_life. Стоит не забывать эту важную особенность WordPress Nonces.

Подделка межсайтовых запросов

Мы часто думаем, что сайты на WordPress получают данные только при отправке данных с форм, таких как формы оформления заказов, редактор постов, редактор профиля пользователя и т.д. Но это не единственный способ, с помощью которого можно отправить HTTP-запрос на сайт.

Как только становится известная структура формы, то можно написать скрипт, который будет имитировать отправку запроса от этой формы. Один из способов сделать это – разместить поддельную форму на другом сайте, откуда отправлять запрос на исходный сайт для вставки вредоносных данных.

Это пример межсайтовой подделки запросов (CSRF). И этого можно в значительной степени избежать, если использовать одноразовые числа. Даже если поддельная форма выглядит один в один, то специальное скрытое поле с одноразовым числом подделать не получится, ведь его содержание нельзя предсказать.

Каждый запрос к сайту WordPress, будь то отправка формы, запрос к admin-ajax.php, Rest API или что-либо еще, что может исходить за пределами сайта, должен защищаться с помощью одноразовых чисел.

Одноразовые числа – часть системы

Имейте ввиду, что проверки одноразового числа недостаточно, чтобы авторизовать запрос, направленный к вашему сайту. Дополнительно необходимо проводить проверку привилегий (capabilities). Рассмотрим следующие 3 примера, где показано сохранение опции из настроек плагина WordPress.

add_action( 'wp_ajax_save_twitter', function(){
    if( isset( $_POST[ 'twitter' ] ) ){
        update_option( 'twitter', strip_tags( $_POST[ 'twitter' ] ) );
    }
});

add_action( 'wp_ajax_save_twitter', function(){
    if( current_user_can( 'mange_options' ) && isset( $_POST[ 'twitter' ] ) ){
        update_option( 'twitter', strip_tags( $_POST[ 'twitter' ] ) );
    }
});
 
add_action( 'wp_ajax_save_twitter', function(){
    if( current_user_can( 'mange_options' ) && isset( $_POST[ 'twitter-save-nonce' ],  $_POST[ 'twitter' ] ) && wp_verify_nonce( $_POST[ 'twitter-save-nonce' ], 'twitter-save-nonce' ) ){
        update_option( 'twitter', strip_tags( $_POST[ 'twitter' ] ) );
    }
});

Первый пример позволяет пользователю любой роли с допустимым файлом cookie обновить эту опцию. Если вы используете этот код на своем сайте, и у меня есть учетная запись подписчика (subscriber), то я могу авторизоваться, получить cookie и затем с помощью консоли браузера или терминала и cURL изменить опцию настроек плагина.

Второй пример в некотором роде лучше, но остается небезопасным. Здесь не используются nonces, но уже есть проверка привилегий текущего пользователя. Без одноразовых чисел этот код по-прежнему подвержен беззащитен перед CSRF-атаками. Это приглашение к фишинг-атаке.

В третьем примере добавляется проверка одноразовых чисел. И это правильно. Если бы у меня были cookie администратора, и я попался бы на фишинг-атаку, то одноразовое число не прошло бы проверку, и не было бы никакого ущерба.

Одноразовые номера применяются вместе с проверкой аутентификации. Нельзя отказаться ни от одного, ни от другого.

Использование WordPress Nonces

В WordPress API есть набор функций, которые позволяют работать с одноразовыми числами. Две самые важные – это wp_create_nonce() и wp_verify_nonce(). Обе могут принимать необязательный аргумент action. Всегда следует использовать уникальный action для каждого запроса. Таким образом, одно nonce нельзя будет использовать для проверки других запросов.

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

<form id="twitter-form">
    <label for="twitter-name">
        <?php esc_html_e( 'Twitter', 'text-domain' ); ?>
    </label>
    <input type="text" id="twitter-name" value="<?php echo esc_attr( get_option( 'twitter', '')  ); ?>" />
    <?php
        wp_nonce_field( 'twitter-save-nonce' );
        submit_button( __( 'Save', 'text-domain' ) );
    ?>
</form>
<script>
    jQuery( document ).ready(function($){
        $( '#twitter-form' ).on( 'click', function(e){
            $.post( ajaxurl, {
                'twitter-save-nonce' : $( '#_wpnonce' ).val(),
                twitter: $( '#twitter-name')
            })
        });
    });
</script>

Это могло бы использоваться на одной из страниц меню в консоли WordPress, доступной только администратору. В результате используемое одноразовое число будет выводиться на экран только для администратора. Таким образом, проверка nonces и привилегий пользователя в функции обратного вызова admin-ajax, совмещенные с проверкой движком WordPress cookie пользователя обеспечивают надежную защиту.

В этом примере мы использовали AJAX для отправки формы, но то же самое будет справедливо и для синхронных HTTP-запросов.

Заключение

На самом деле, это все, что нужно знать для использования WordPress Nonces. Используйте их, злоупотребляйте ими. Если есть сомнения, используйте их. Когда вы думаете, что они вам не нужны, в любом случае, используйте их. Если кто-то говорит вам не использовать одноразовые числа, используйте их все равно.

Есть еще два момента, о которых я хочу рассказать перед тем, как закончу.

В отношении одноразовых чисел важно помнить, что одним из компонентов одноразового числа является идентификатор текущего пользователя, или 0, если он не вошел в систему. Это означает, что nonces не могут передаваться между пользователями. Таким образом, не произойдет такого, что одноразовое число уже было проверено до того, как пользователь авторизуется. Но эта проблема возникает, если одноразовое число используется вместе с одноразовым числом WordPress Rest API, который проверяет подлинность cookie.

Другая важная вещь, которую следует помнить, это то, что nonces подвержены атакам по времени PHP. Именно поэтому WordPress использует неэффективную функцию hash_equals() вместо простого сравнения строк. Может возникнуть соблазн проверить одноразовое число, сгенерировав ожидаемое значение и используя сравнение строк. Никогда не делайте этого. И не пытайтесь изменить механизм проверки одноразовых чисел.

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

Источник