3.5 Одноразовые числа (nonces)

Nonces – это генерируемые числа, используемые для проверки происхождения и интента (намерение) запросов в целях безопасности. Каждое число может быть использована только один раз.

Nonce так и расшифровывается – «число, используемое один раз» (англ. – number used once). Некоторые пользователи называют их токенами.

Если ваш плагин позволяет пользователям предоставлять данные; будь то на стороне администратора или на публичной стороне; вы должны убедиться, что пользователь тот, за кого он себя выдает, и что у него есть необходимые возможности для выполнения этого действия. Выполнение обоих действий в тандеме означает, что данные изменяются только тогда, когда пользователь ожидает их изменения.

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

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

Проверка возможности гарантирует, что только пользователи, имеющие разрешение на удаление сообщения, могут его удалять. Но что, если кто-то обманом заставит вас нажать на эту ссылку? У вас есть необходимая возможность, поэтому вы можете непреднамеренно удалить сообщение.

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

Когда вы генерируете ссылку delete (удалить), вы захотите использовать функцию wp_create_nonce() для добавления одноразового числа в ссылку, аргумент, переданный в функцию, гарантирует, что создаваемое число уникально для данного конкретного действия.

Затем, когда вы обрабатываете запрос на удаление ссылки, вы можете проверить, что nonce тот, который вы ожидаете.

Для более подробной информации, рекомендую перевод хорошей статьи Марка Жакита про одноразовые числа.

Подробный пример

Полный пример с использованием проверок возможностей, проверки данных, безопасного ввода, безопасного вывода и одноразовых чисел:

<?php
/**
 * generate a Delete link based on the homepage url
 */
function wporg_generate_delete_link($content)
{
    // run only for single post page
    if (is_single() && in_the_loop() && is_main_query()) {
        // add query arguments: action, post, nonce
        $url = add_query_arg(
            [
                'action' => 'wporg_frontend_delete',
                'post'   => get_the_ID(),
                'nonce'  => wp_create_nonce('wporg_frontend_delete'),
            ],
            home_url()
        );
        return $content . ' <a href="' . esc_url($url) . '">' . esc_html__('Delete Post', 'wporg') . '</a>';
    }
    return null;
}
 
/**
 * request handler
 */
function wporg_delete_post()
{
    if (
        isset($_GET['action']) &&
        isset($_GET['nonce']) &&
        $_GET['action'] === 'wporg_frontend_delete' &&
        wp_verify_nonce($_GET['nonce'], 'wporg_frontend_delete')
    ) {
 
        // verify we have a post id
        $post_id = (isset($_GET['post'])) ? ($_GET['post']) : (null);
 
        // verify there is a post with such a number
        $post = get_post((int)$post_id);
        if (empty($post)) {
            return;
        }
 
        // delete the post
        wp_trash_post($post_id);
 
        // redirect to admin page
        $redirect = admin_url('edit.php');
        wp_safe_redirect($redirect);
 
        // we are done
        die;
    }
}
 
if (current_user_can('edit_others_posts')) {
    /**
     * add the delete link to the end of the post content
     */
    add_filter('the_content', 'wporg_generate_delete_link');
 
    /**
     * register our request handler with the init hook
     */
    add_action('init', 'wporg_delete_post');
}

Наверх ↑