Using WordPress Nonces
Drazen

Drazen

Published on: February 29th, 2024.

Using WordPress Nonces

A nonce (number used once) is a random, unpredictable value generated for a specific action or request. In the context of WordPress, nonces are unique tokens attached to forms, URLs, and other actions. These tokens act as a one-time verification mechanism to prevent unauthorized actions or data manipulation.

How do Nonces Work in WordPress?

When a user interacts with your WordPress website, for example, submitting a form or performing an action like updating a post, a nonce is generated and attached to the request. This nonce is typically sent as a hidden form field or included in the URL as a parameter.

When the request is received by WordPress, it validates the provided nonce against the one stored in the database for that specific action. If the nonces match, the action is deemed legitimate and proceeds as expected. However, if the nonces don't match, WordPress recognizes the request as potentially malicious and rejects it, preventing unauthorized modifications or actions.

Benefits of Using Nonces

Using nonces in WordPress offers several key advantages:

  • Prevents CSRF (Cross-Site Request Forgery) Attacks: CSRF attacks attempt to trick a user's browser into performing unauthorized actions on a website they're already logged into. Nonces help mitigate this risk by ensuring that only legitimate requests with valid nonces can be processed.
  • Protects Forms and Actions: Nonces safeguard forms and other actions from being submitted unintentionally or maliciously. They add an extra layer of security by requiring valid nonces for any action to be completed.
  • Enhanced Security: Nonces contribute to an overall more secure WordPress environment by acting as an additional security measure against various attack vectors.

Best Practices for Nonces

Here are some recommended practices for using nonces effectively in your WordPress development:

  1. Always Use Nonces for Forms and Critical Actions: Protect any form submissions and important actions with nonces.
  2. Verify Nonces on the Server-Side: Prevent attackers from manipulating the nonce values in the browser by verifying nonces server-side.
  3. Use Appropriate Nonce Verification Functions: Utilize WordPress-provided functions like wp_verify_nonce() and check_admin_referer() for verification.
  4. Consider Plugin Recommendations: Use plugins that offer additional security features and follow best practices related to nonces.

How to use nonces?

The implementation of nonces depends on the context of data submission, whether from the frontend (user-facing part) or backend (dashboard for administrators/editors). You can also submit data via various request methods (mainly POST and GET).

Admin POST nonce implementation

Let's say we have a form which adds a new job opening to the database via the WordPress dashboard. To achieve this, we need a form for administrators and/or editors to add new jobs. Here's an example:

1<!-- Has to be the admin-post.php file -->
2<form
3  method="post"
4  action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"
5>
6  <!-- These fields don't need to be visible -->
7  <input type="hidden" name="action" value="add_job_action"/>
8  <input type="text" name="job_name" required="required" />
9  <input type="number" name="salary" required="required" />
10
11  <!-- This adds the nonce field! The parameter is the nonce action name. -->
12  <?php wp_nonce_field( 'add_job_nonce' ); ?>
13
14  <button type="submit">Add job</button>
15</form>
16

Now we have to implement the logic which will handle the form submission. Add the following code:

1/**
2 * Checks the nonce, then adds the job.
3 *
4 * @return void
5 */
6function my_plugin_add_job(): void {
7  // Verify the nonce.
8  check_admin_referer( 'add_job_action' );
9
10  // Store the job in the database...
11}
12
13add_action( 'admin_post_add_job_action', 'my_plugin_add_job' );
14

The check_admin_referer() WordPress function will validate the nonce from the request and check if the generated value really came from the dashboard. If it didn't, the process will exit, and you will see an error message. If the nonce was genuine then the function execution will continue.

AJAX nonce implementation

Another way to send a request to the server is via an AJAX request. Similar to the Admin POST method above, all AJAX requests are sent to a central PHP file in WordPress.

First things first, you need to create the nonce and pass it to JavaScript:

1/**
2 * Enqueues the "my-script.js" file in both the frontend and dashboard.
3 *
4 * @return void
5 */
6function enqueue_my_script(): void {
7  // Enqueue the "my-script.js" file under version 1.0.0 with no dependencies.
8  wp_enqueue_script( 'my-script', '/path/to/my-script.js', array(), '1.0.0', true );
9
10  // Pass the ajax URL and the nonce to the JavaScript file.
11  wp_localize_script(
12    'my-script',
13    // "myData" can be called anything you want.
14    'myData',
15    array(
16      // We need the URL to the admin-ajax.php file in the frontend.
17      'ajaxUrl' => admin_url( 'admin-ajax.php' ),
18      // The parameter is the nonce action name.
19      'nonce'   => wp_create_nonce( 'update_job_nonce' ),
20    )
21  );
22}
23
24// Frontend hook.
25add_action( 'wp_enqueue_scripts', 'enqueue_my_script' );
26
27// Backend hook.
28add_action( 'admin_enqueue_scripts', 'enqueue_my_script' );
29

In this example we enqueued the JavaScript file in both frontend and dashboard, if this is not desirable then just leave the hook out you don't need. Now we need to send the nonce back to the server alongside the other form data:

1jQuery.ajax({
2  // This could also be a GET request, depending on your request.
3  method: 'POST',
4  data: {
5    action: 'update_job_action',
6    // We use "_ajax_nonce" because the WordPress function expects to find it
7    // under this key.
8    _ajax_nonce: myData.nonce,
9    // Here goes the other data...
10    jobName: 'Prince of all Saiyans',
11    salary: 9001
12  }
13});
14

And finally, we need a function which will handle the request above, but not before validating the nonce!

1/**
2 * Checks the nonce, then updates the job.
3 *
4 * @return void
5 */
6function my_plugin_update_job(): void {
7  // Make sure that the action name matches the action from the
8  // JavaScript file!
9  check_ajax_referer( 'update_job_action' );
10
11  // Update the existing job...
12}
13
14// This hook allows the request to be sent from the frontend.
15add_action( 'wp_ajax_nopriv_update_job_action', 'my_plugin_update_job' );
16
17// This hook allows the request to be sent from the dashboard.
18add_action( 'wp_ajax_update_job_action', 'my_plugin_update_job' );
19

In the example above we enabled the request for both the frontend and the dashboard. If this is undesirable, then leave one of the hooks out.

Conclusion

In this day and age it's important to utilize every security feature at your disposal. WordPress' nonces are a simple and yet effective way of protecting your website against CSRF attacks. Remember, security is an ongoing process, so staying informed about best practices and keeping your WordPress core and plugins updated is crucial for maintaining a secure website.