An in-depth guide on using Ajax with WordPress

WordPress Nonces and Why They Are Useful

Helping secure WordPress is always a good thing. The golden rule of WordPress security is, “Never trust anyone, even yourself.”

Security involves making sure requests have originated from the correct location. The use of WordPress nonces assist in securing your WordPress plugin or theme. And using them with Ajax requests is a must. Let’s begin with why you should care about nonces.

Why are Nonces Useful?

Ever heard of Cross-Site Request Forgery (CSRF) attacks? Me neither before I learned about WordPress nonces.

A CSRF attack is when you are tricked into performing an action while authenticated. Say, for example, a malicious plugin is on your site. They send you an email with a URL that has a payload that will delete all of your users. Since you’re logged in and have clicked the link, you have unintentionally deleted all of your users. Hackers: 1. You: 0.

CSRF Attack Example
CSRF Attack Example

Nonces help protect against this kind of malicious attack. For example, what if deleting users requires nonce verification? Since the malicious person sending the email doesn’t know the nonce, you are given a standard WordPress message asking if you’re sure you want to perform the action. In this case, a CSRF attack is prevented.

CSRF Attack with Nonces
CSRF Attack with Nonces

In summary, nonces prevent Cross-Site Request Forgery attacks. And with Ajax, they’re helpful to ensure that unauthorized Ajax attacks are stopped at the source, preventing denial of service attacks (well, one would hope) and inadvertent code from running on your server.

Okay, so that didn’t make a whole lot of sense, did it? Let’s use a real-life analogy to hammer this concept home.

You have checked into a hotel and are given an electronic room key for room 215.

What if, while you’re out on the town, you drop your room key? The room isn’t printed on the card, so you’re theoretically safe. The room number is your nonce.

Furthermore, this room key expires the moment you check out or request a new room key. This renders the “nonce” as expirable, thus rendering the room key good for only a short period of time.

The room key is your nonce, and each nonce is associated with an action. In this example, the action is, “Open room 215.”

If someone were to somehow enter your room, it would be a matter of luck. The person with the room key would have to try each individual room of the hotel before coming to access your actual room.

Nonces behave almost the same way. They are associated with a specific action, have an expiration, and require a specific key (in the form of a unique string) that will allow the action to proceed.

Nonces are valid for only 24 hours and the keys change every 12 hours. So nonces are great to stop attack vectors. So what are the ideal situations when nonces should be used?

  • When performing actions in an administrative panel (plugin setting pages, theme settings pages, custom meta for posts, etc.).
  • When storing items in the WordPress database.
  • When retrieving items from the WordPress database that require a logged-in status (profile information, options, etc.).
  • When doing a capability check during a REST API call.

As a reminder, nonces are action-based. If this action needs protection, then nonces are necessary to ensure the request originated legitimately.

Now that the nonce terminology is out of the way, what are some of the applications for using nonces?

Nonces and Forms

When using nonces with forms, you can make use of the WordPress function wp_nonce_field. The function wp_nonce_field takes in four arguments, all of which are optional.

<?php wp_nonce_field( $action, $name, $referer, $echo ); ?> 
  • $action – The nonce action you would like to take. An example could be: my_plugin_form_submission.
  • $name – The nonce name (default is _wpnonce). I recommend always using this parameter since WordPress’s default is _wpnonce and you wouldn’t want to conflict (especially when creating forms in the WordPress admin area).
  • $referer – A boolean on whether to set the referer field or not. I usually just set this to true.
  • $echo – Whether to echo out the result, or return it (default is true). If you are creating a form as a shortcode or as a string and need the result returned, set this option to false.

Here’s an example self-submitting form that I’ve placed in a WordPress page template (you could use a shortcode instead if you so desire).

<form id='registration-form' method="post">
	<?php wp_nonce_field( 'submit-form-registration', '_registration_nonce', true, true ); ?>
	<!--form data-->
	<input type='submit' value='Submit Registration' name='registration-submit' id='registration-submit' />
</form>

The above code has a nonce field that is echoed out. The action name is submit-form-registration and the nonce name is _registration_nonce.

The form posts to itself (i.e., on the same page), so when we begin processing the form data, we would make use of the check_admin_referer WordPress function to verify the nonce.

<?php
if ( isset( $_POST['registration-submit'] ) ) :
	check_admin_referer( 'submit-form-registration', '_registration_nonce' );
	echo "Success!";
endif;
?>
<form id='registration-form' method="post">
	<?php wp_nonce_field( 'submit-form-registration', '_registration_nonce', true, true ); ?>
	<!--form data-->
	<input type='submit' value='Submit Registration' name='registration-submit' id='registration-submit' />
</form>

The check_admin_referer function takes in two arguments: the nonce action and the nonce name. If the nonce isn’t valid, WordPress outputs a message saying the link has expired.

An alternative to check_admin_referer is wp_verify_nonce.

<?php
if ( isset( $_POST['registration-submit'] ) ) :
	if ( wp_verify_nonce( $_REQUEST['_registration_nonce'], 'submit-form-registration' ) ) {
		echo 'Nonce verified!';
	} else {
		echo 'Nonce not verified';
	}
endif;
?>
<form id='registration-form' method="post">
	<?php wp_nonce_field( 'submit-form-registration', '_registration_nonce', true, true ); ?>
	<!--form data-->
	<input type='submit' value='Submit Registration' name='registration-submit' id='registration-submit' />
</form>

I actually prefer wp_verify_nonce over check_admin_referer as wp_verify_nonce has a lot more use-cases than just form validation and you can control the output better than check_admin_referer. In the end, it’s up to you how you want to verify nonces.

Nonces and URLs

If you have comments enabled on your site, chances are you have received emails when someone leaves a comment on a post. These comment emails contain several links, notably the ones to delete or mark the comment as spam. These links have nonces attached to them.

There are two helper functions worth mentioning that will help you create a link that has a nonce attached: wp_nonce_url and wp_create_nonce.

Once again, I just created a page template that spits out a link. The link (when clicked) goes to the same page, but with a nonce variable attached as a GET variable instead of a POST one.

The wp_nonce_url function takes in two arguments: the URL to visit, and the nonce action.

Here’s some sample front-end code:

<?php
if ( isset( $_GET['_wpnonce'] ) ) :
	if ( wp_verify_nonce( $_REQUEST['_wpnonce'], 'sample-link-option' ) ) {
		echo 'Nonce verified!';
	} else {
		echo 'Nonce not verified';
	}
endif;
?>
<?php
$url = wp_nonce_url( get_permalink(), 'sample-link-option' );
?>
<a href="<?php echo esc_url( $url ); ?>">This is my test link</a>

The nonce action used here is called sample-link-option. When clicked, the nonce is checked.

Let’s modify the above code to use wp_create_nonce instead. The wp_create_nonce function only takes in one argument, which is the nonce action name.

<?php
if ( isset( $_GET['_wpnonce'] ) ) :
	if ( wp_verify_nonce( $_REQUEST['_wpnonce'], 'sample-link-option' ) ) {
		echo 'Nonce verified!';
	} else {
		echo 'Nonce not verified';
	}
endif;
?>
<?php
$url = add_query_arg(
	array(
		'_wpnonce' => wp_create_nonce( 'sample-link-option' ),
	),
	get_permalink()
);
?>
<a href="<?php echo esc_url( $url ); ?>">This is my test link</a>

So when would you use wp_create_nonce over wp_nonce_url? It’s all about control, as in the case of check_admin_referer and wp_verify_nonce.

Both will get you the same result, but wp_create_nonce gives you more control on naming the nonce name and forming the URL.

Nonces and Ajax

Nonces and Ajax aren’t exactly straightforward, but you’ll see how Ajax nonces are implemented throughout the various Ajax examples in later chapters.

Basically, you would create either a nonce in a form field or as a URL (using the techniques already presented in this chapter) and use JavaScript to capture the nonce value.

You would then use Ajax to pass this nonce value to your Ajax processer. The Ajax processor will then verify the nonce.

The two functions to assist you in verifying Ajax nonces are: check_ajax_referer (same arguments as check_admin_referer) and (slightly repeating myself) wp_verify_nonce. Once again, I prefer wp_verify_nonce as I have more control over the output.

The check_ajax_referer function assumes a $_REQUEST variable of _ajax_nonce. With wp_verify_nonce, the nonce variable can be defined in the function call.

So which is better? It’s your call.

Conclusion

In this chapter, you learned why nonces are important in order to prevent one attack vector: CSRF. You learned the various helper functions for creating nonces and how to verify that they indeed work.

In the next chapter, I’ll go over more security options that WordPress provides out-of-the-box. Then, we’ll finally get to creating your first Ajax call.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top