Статьи

Что такое одноразовые номера WordPress?

Сохранение вашей темы WordPress или кода плагина важно для предотвращения возможных атак со стороны злоумышленников.

Ранее мы уже рассматривали, как санировать, экранировать и проверять данные формы в WordPress , а также улучшить качество вашей темы WordPress с помощью VIP-сканера .

Сегодня мы рассмотрим, как одноразовые номера (число, использованное один раз) также может помочь защитить ваши темы WordPress и плагины.

Что такое одноразовые номера WordPress?

Одноразовые номера WordPress определяются как:

… «Номер, использованный один раз», чтобы помочь защитить URL-адреса и формы от определенных типов неправомерного использования, злонамеренного или иного.
https://codex.wordpress.org/WordPress_Nonces

Хотя в WordPress одноразовый номер технически не является числом (это хэш, состоящий из букв и цифр), он помогает предотвратить выполнение действий злоумышленниками.

Одноразовые номера WordPress работают в двух частях:

  • Создание одноразового номера (хеш), отправка его через форму или действие, и
  • Проверка одноразового номера перед принятием данных формы или выполнением действия.

Например, когда вы собираетесь удалить сообщение на экране администрирования WordPress, вы заметите, что URL содержит параметр _wpnonce :
http://127.0.0.1/tuts/wp-admin/post.php?post=542&action=trash&_wpnonce=a03ac85772

Подпрограмма, которая удаляет сообщение, проверит, что сообщение 542 имеет одноразовое значение a03ac85772 перед удалением сообщения. Если одноразовый номер не существует или не соответствует ожидаемому значению, сообщение не будет удалено.

Это предотвращает возможность удаления злоумышленником большого количества сообщений. Например, следующее не будет работать, так как одноразовый номер принадлежит идентификатору записи 542:
http://127.0.0.1/tuts/wp-admin/post.php?post=642&action=trash&_wpnonce=a03ac85772 http://127.0.0.1/tuts/wp-admin/post.php?post=742&action=trash&_wpnonce=a03ac85772 http://127.0.0.1/tuts/wp-admin/post.php?post=842&action=trash&_wpnonce=a03ac85772

Вы уверены, что хотите это сделать

Давайте теперь посмотрим, как мы можем реализовать одноразовые слова WordPress в плагине.

Настройка нашего плагина WordPress

Давайте начнем с основного плагина, который имеет собственный экран настроек. На экране настроек есть поле, которое можно отправить и сохранить в таблице параметров WordPress.

Введите приведенный ниже код в новый файл по адресу wp-content/plugins/implementing-wordpress-nonces/implementing-wordpress-nonces.php :

 plugin = new stdClass; $this->plugin->name = 'implementing-wordpress-nonces'; // Plugin Folder $this->plugin->displayName = 'Nonces'; // Plugin Name add_action( 'admin_menu', array( &$this, 'admin_menu' ) ); } /** * Register the plugin settings panel * * @since 1.0.0 */ function admin_menu() { add_menu_page( $this->plugin->displayName, $this->plugin->displayName, 'manage_options', $this->plugin->name, array( &$this, 'admin_screen' ), 'dashicons-admin-network' ); } /** * Output the Administration Screens * Save POSTed data from the Administration Panel into a WordPress option * * @since 1.0.0 */ function admin_screen() { // Save Settings if ( isset( $_REQUEST['submit'] ) ) { update_option( 'implementing_wordpress_nonces', sanitize_text_field( $_REQUEST[ 'implementing_wordpress_nonces' ] ) ); $message = __( 'Settings saved', $this->plugin->name ); } // Output form ?> 

plugin-> DISPLAYNAME; ?>

Активируйте плагин через экран администрирования WordPress> Плагины, и вы увидите новый пункт меню Nonces :
одноразовые

Нажмите здесь, и вы попадете на экран настроек с одним полем:
одноразовые

Введите любое значение, нажмите «Сохранить», и, если все работает, вы увидите подтверждение вместе со значением, которое вы только что ввели:
одноразовые

Демонстрация недостатка безопасности

Введите следующий URL в адресную строку вашего веб-браузера (заменив домен тем, где у вас установлен WordPress):
http://127.0.0.1/tuts/wp-admin/admin.php?page=implementing-wordpress-nonces&implementing_wordpress_nonces=abc

Обратите внимание, что случилось? Значение было сохранено как abc , просто путем прямого доступа к URL и входа в WordPress:
одноразовые

Хотя мы могли бы использовать $_POST вместо $_REQUEST в нашем коде (мы использовали $_REQUEST чтобы упростить демонстрацию проблемы безопасности), это не помогло бы - злоумышленник все равно мог бы, либо самостоятельно, либо обмануть вас при переходе по ссылке - вам нужно отправить запрос POST на этот экран, в результате чего значение параметра будет изменено.

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

Теперь мы создадим и подтвердим одноразовый номер WordPress, чтобы предотвратить возможную атаку.

Обеспечение нашего плагина одноразовым

Как упоминалось ранее, есть два шага к процессу: во-первых, нам нужно создать одноразовый номер, который будет отправлен с нашей формой. Во-вторых, нам нужно проверить этот одноразовый номер при отправке формы.

Чтобы создать одноразовое поле в нашей форме, мы можем использовать wp_nonce_field() :

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

Добавьте следующий код чуть выше нашей кнопки ввода:

[php] wp_nonce_field ('Implelling_wordpress_nonces_save','ring_wordpress_nonces_nonce ');

wp_nonce_field принимает четыре аргумента — первые два наиболее важны:

  • $action : определяет конкретное действие, которое мы выполняем, и должно быть уникальным. Хорошей практикой является добавление префикса к имени вашего действия, так как потенциально может выполняться несколько действий. В этом случае мы что-то сохраняем, поэтому мы использовали implementing_wordpress_nonces_save
  • $name : определяет имя скрытого поля, созданного этой функцией. Как и выше, мы добавили к этому имени нашего плагина префикс, поэтому назвали его implementing_wordpress_nonces_nonce

Если мы перезагрузим экран настроек, изменим наше значение и нажмем кнопку Сохранить, вы заметите, что значение все еще меняется. Теперь нам нужно реализовать проверку для одноразового поля, которое было отправлено, используя wp_verify_nonce( $name, $action ) :

Убедитесь, что одноразовый номер является правильным и не имеет срока действия в отношении указанного действия. Функция используется для проверки одноразового номера, отправленного в текущем запросе, к которому обычно обращается переменная PHP $ _REQUEST.

Замените раздел Save Settings функции нашего плагина admin_screen() на код ниже:

 // Save Settings if ( isset( $_REQUEST['implementing_wordpress_nonces'] ) ) { if ( isset( $_REQUEST[ 'implementing_wordpress_nonces_nonce' ] ) && wp_verify_nonce( $_REQUEST[ 'implementing_wordpress_nonces_nonce' ], 'implementing_wordpress_nonces_save' ) ) { update_option( 'implementing_wordpress_nonces', sanitize_text_field( $_REQUEST[ 'implementing_wordpress_nonces' ] ) ); $message = __( 'Settings saved', $this->plugin->name ); } else { // Nonce could not be verified - bail wp_die( __( 'Invalid nonce specified', $this->plugin->name ), __( 'Error', $this->plugin->name ), array( 'response' => 403, 'back_link' => 'admin.php?page=' . $this->plugin->name, ) ); } } 

Этот код выполняет несколько действий:

  • Во-первых, он проверяет, что мы отправили что-то.
  • Затем он проверяет, существует ли наше поле nonce, и, если это так, пытается проверить значение nonce относительно ожидаемого нами действия.
  • Если проверки пройдены, опция обновляется.
  • Если проверки не пройдены, мы выдаем ошибку 403 с сообщением «Указан неверный одноразовый номер».

Чтобы убедиться, что наши одноразовые номера создаются и проверяются, давайте попробуем снова обратиться к нашему «вредоносному» прямому URL:
http://127.0.0.1/tuts/wp-admin/admin.php?page=implementing-wordpress-nonces&implementing_wordpress_nonces=abc .

Если наши одноразовые номера реализованы и проверяются, вы увидите уведомление о недействительном указанном одноразовом номере :
одноразовые

Использование одноразовых номеров в AJAX-запросах

Скажем, мы хотим сохранить изменения с помощью вызова AJAX, а не перезагружать весь экран. Мы можем сделать это с помощью нескольких настроек кода.

Сначала давайте загрузим JavaScript в наш плагин и зарегистрируем обработчик AJAX, добавив следующее в нашу __construct() :

 add_action( 'admin_enqueue_scripts', array( &$this, 'admin_scripts_css' ) ); add_action( 'wp_ajax_implementing_wp_nonces', array( &$this, 'admin_ajax_save' ) ); 

В нашем классе добавьте соответствующую функцию admin_scripts_css :

 /** * Register and enqueue any JS and CSS for the WordPress Administration * * @since 1.0.0 */ function admin_scripts_css() { // JS wp_enqueue_script( $this->plugin->name, plugin_dir_url( __FILE__ ) . 'admin.js', array( 'jquery' ), '1.0', true ); } 

Для нашего вызова AJAX добавьте соответствующую функцию admin_ajax_save :

 /** * Saves POSTed settings data * * @since 1.0.0 */ function admin_ajax_save() { // Save option and return 1 update_option( 'implementing_wordpress_nonces', sanitize_text_field( $_REQUEST[ 'implementing_wordpress_nonces' ] ) ); echo 1; die(); } 

Наконец, нам нужно создать новый файл в нашей папке плагинов для нашей подпрограммы JavaScript, которая будет отправлять данные через AJAX при отправке формы. Давайте сделаем это, создав новый файл с именем admin.js , вставив следующее:

 jQuery( document ).ready( function( $ ) { $( 'form#implementing-wordpress-nonces' ).submit( function( e ) { // Prevent form submission e.preventDefault(); // Submit form via AJAX $.post( ajaxurl, // Set by WordPress { 'action': 'implementing_wp_nonces', 'implementing_wordpress_nonces': $( 'input#implementing_wordpress_nonces' ).val() }, function(response) { if ( response ) { alert( 'Settings Saved' ); } } ); }); } ); 

Перезагрузите наш экран настроек, и если все сработает, при отправке формы вы получите на экране подтверждение о том, что настройки сохранены.
одноразовые

Мы можем перезагрузить экран настроек еще раз, чтобы убедиться, что значение обновилось успешно:
одноразовые

Опять же, теперь нам нужно реализовать как создание, так и проверку одноразового номера WordPress, чтобы гарантировать, что CSRF-атаки не могут быть выполнены с помощью AJAX-запроса.

Для создания одноразовых номеров для запросов AJAX мы можем использовать функцию WordPress wp_create_nonce :

Генерирует и возвращает одноразовый номер. Одноразовый номер генерируется на основе текущего времени, аргумента $ action и текущего идентификатора пользователя.

Он принимает один аргумент $action , поэтому мы будем использовать:

 $nonce = wp_create_nonce( 'implementing_wordpress_nonces_ajax_save' ); 

Чтобы wp_localize_script() этот одноразовый хэш в область действия JavaScript, мы можем использовать wp_localize_script() для отправки объекта JS. Давайте добавим следующий код ниже вызова wp_enqueue_script в нашем плагине:

 wp_localize_script( $this->plugin->name, 'implementing_wordpress_nonces', array( 'nonce' => wp_create_nonce( 'implementing_wordpress_nonces_ajax_save' ), ) ); 

Нам также необходимо обновить наш файл JavaScript для отправки этого одноразового значения с помощью запроса AJAX POST:

 jQuery( document ).ready( function( $ ) { $( 'form#implementing-wordpress-nonces' ).submit( function( e ) { // Prevent form submission e.preventDefault(); // Submit form via AJAX $.post( ajaxurl, // Set by WordPress { 'action': 'implementing_wp_nonces', 'nonce': implementing_wordpress_nonces.nonce, 'implementing_wordpress_nonces': $( 'input#implementing_wordpress_nonces' ).val() }, function(response) { if ( response == 1 ) { alert( 'Settings Saved' ); } else { alert( 'Invalid nonce specified' ); } } ); }); } ); 

Файл JavaScript теперь отправляет переменную $_POST именем nonce со значением wp_create_nonce .

Наконец, нам нужно проверить одноразовый номер при отправке в запросе AJAX. Обновите нашу функцию admin_ajax_save :

 /** * Saves POSTed settings data * * @since 1.0.0 */ function admin_ajax_save() { // Run a security check first. check_ajax_referer( 'implementing_wordpress_nonces_ajax_save', 'nonce' ); // Save option and return 1 update_option( 'implementing_wordpress_nonces', sanitize_text_field( $_REQUEST[ 'implementing_wordpress_nonces' ] ) ); echo 1; die(); } 

При этом используется check_ajax_referer , который проверяет, существует ли заданное $action ( check_ajax_referer ) для заданного поля POST $name (nonce).

Если это не удастся, будет возвращено -1, в результате чего наш файл JavaScript отобразит предупреждение:

одноразовые

Если это успешно, 1 будет возвращено, вызывая наш файл JavaScript, чтобы показать сообщение об успехе:

одноразовые

Вывод

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

Используя wp_nonce_field() и wp_verify_nonce , мы показали, как проверять одноразовые номера для предотвращения CSRF-атак. Наконец, мы реализовали сохранение POST-данных в AJAX и использовали wp_create_nonce и check_ajax_referer чтобы гарантировать, что наши AJAX-запросы также будут максимально безопасными.

Полный исходный код можно найти в репозитории GitHub или загрузить код напрямую .