Blog de programación, errores, soluciones

Chose Language:
Author: Admin/Publisher |finished | checked

WordPress CSRF protection

The CSRF protection on WordPress is what allows us to create a secure form on a page, section, article, etc., and it is quite important. It’s been a long time since WordPress was used only for writing what we think or want to share with the reader.

Keep in mind that the user will need to perform at least one search, as in this site; this blog tends to publish things that I find interesting or that may help others, which is why it only has one search.

But if you are interested in creating forms without risking your WordPress being hacked or suffering from XSS attacks, you should use various WordPress functions in your plugin or theme.

These functions include wp_nonce_field, wp_verify_nonce, and check_admin_referer.

wp_nonce_field

This function will return a hidden field for forms; it may or may not display it depending on the fourth parameter, whether it’s true or false. If this parameter is false, we will need to display its result ourselves.

For example, if we use:

$form_nonce = wp_nonce_field('X_form', 'X_nonce', true, false);

We should display it using echo afterward.

Now, let’s look at its description.

Description / Descripción
wp_nonce_field( int|string $action = -1, string $name = '_wpnonce', bool $referer = true, bool $display = true ): string

Note that by default, the parameters will be as follows:

  • $action: Its default value will be -1, indicating that there will be no action. In our case, we should give it a value, for example, "formA"
  • $name: It will have the value "_wpnonce"
  • $referer: It will have a value of true.
  • $display: It will be true.

Therefore, if we use the wp_nonce_field function with only the first parameter, it will automatically display on the screen. When we need to check the nonce, we can do so with $_POST['_wpnonce'].

Let’s create a form: Suppose we need to create a newsletter form, for which we would require the user’s email and their preference for receiving our emails periodically, for example, daily, weekly, or monthly.

<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Formulario de Newsletter</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }

        form {
            max-width: 400px;
            margin: auto;
        }

        label {
            display: block;
            margin-bottom: 8px;
        }

        input, select {
            width: 100%;
            padding: 10px;
            margin-bottom: 15px;
            box-sizing: border-box;
        }

        button {
            background-color: #4CAF50;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>

    <h2>Newsletter Form</h2>
    <p>Subscribe to our newsletter and choose the sending frequency:</p>

    <form action="procesar_formulario.php" method="post">
        <label for="name">Name:</label>
        <input type="text" id="name" name="name" required>

        <label for="email">Correo electrónico:</label>
        <input type="email" id="email" name="email" required>

        <label for="frequency#34;>delivery Frequency:</label>
        <select id="frequency" name="frequency">
            <option value="daily">Diaria</option>
            <option value="weekly">Semanal</option>
            <option value="monthly">Mensual</option>
        </select>

        <button type="submit" name="submit" value="Suscribirse" >Suscribirse</button>
    </form>

</body>
</html>
newsletter form

Now we should add our CSRF protection to our form. We can do this by adding the following below the
tag:

<?php echo wp_nonce_field('formA'); ?>

wp_verify_nonce

With this function, we will verify that a secure nonce has been used, which has a time limit.

Description / Descripción
wp_verify_nonce( string $nonce, string|int $action = -1 ): int|false

If we continue with the action we set in our wp_nonce_field function, our action here should be "formA". Remember that we haven’t specified a nonce, so our nonce value will be in $_GET['_wpnonce'] or $_POST['_wpnonce'], depending on the method we use in the form.

if (isset($_POST['submit'])) {
    // Check the nonce
    $nonce = $_POST['_wpnonce'];
    if (wp_verify_nonce($nonce, "formA")) {
        // Process the form data
    } else {
        // Handle the error
    }
}

Note that in this example, we are using isset($_POST['submit']). This way, I know that I have clicked the button, saving time in directly checking the nonce. In essence, I already know that $_POST['_wpnonce'] exists.

You can check about PHP isset at https://blastcoding.com/en/php-isset-function/

Then, we check our nonce with the wp_verify_nonce function. If it returns true, we proceed with the form process, which involves validation and data storage.

check_admin_referer

We will use the check_admin_referer function if we are developing a plugin, as this function will check whether our page is being referred from another admin page and verify if the nonce is correct.

Description / Descripción
check_admin_referer( int|string $action = -1, string $query_arg = '_wpnonce' ): int|false
// chequeo el submit
if (isset($_POST['submit'])) {
    check_admin_referer('accion', 'nonce_name');
    // Si llegamos aquí, el nonce es válido, ya podemos porcesar los datos del formulario
    // ...
}

If the nonce is invalid, in theory, the function will call die(), printing "Are you sure?" on the screen before die function.

Category: en-wordpress
Something wrong? If you found an error or mistake in the content you can contact me on Twitter | @luisg2249_luis.
Last 4 post in same category