The Word of the Day Is "Nonce"
What is it?
What is it?... - Epic, Faith No More
In recent years, we've seen a proliferation of new terms and expressions to describe all of the new activities that people engage in. Unsurprisingly, a lot of these words are related to technology. For instance, selfie (Oxford dictionary word of the year!), hackerspace, and phablet all made the list for 2013. Some words, are more esoteric in usage. One such word is "Nonce". You may not have heard of nonces yet, but, as we'll learn here today, they can be of great use in securing Web applications. By the time we're done here today, you'll be throwing the nonce word around like some people name drop when they want to impress people, only without people being embarrassed for you!
What Is It?
The word Nonce is actually a sort of acronym and is short for "Number used ONCE". It serves as an extra security measure on top of user credentials and access rights to protect against certain actions launched from a website. The goal is to help prevent malicious attacks against the system by preventing actions initiated by links or HTTP requests from being utilized more than once. It works much like the numbering systems at your local butcher shop or medical laboratory. You take a number from the dispenser and wait for your number to be called. Afterwards, you throw away the number. With respect to nonces, every time a link or a form is transmitted to the browser, a key/value pair is embedded. When the link is activated or the form is submitted, server-side code checks for the key/value pair and then authenticates it. If the nonce checks out, the action is performed, if it doesn't or the nonce is missing, the action is not performed and a security error results.
The Nuts-and-bolts of Nonce Creation
While nonce formats are unstandardized at this point, most libraries employ the following pieces of information in generating a nonce:
- A secret key or 'salt' stored only on the server
- The user ID (this associates the nonce to a specific user)
- An action name: i.e., 'delete-post'
- A timestamp (so that the nonce expires if not used within a short time frame)
- A datasource of used nonces (so that each nonce is unique)
A nonce may be generated using the following combination: secret-salt + user ID + action-name + timestamp. The resulting string is run through a one-way hash algorithm before being embedded into the HTML markup. Here is the HTML markup of a link with a nonce included:
<a href="delete_post.php?post=2112&_nonce=9c2fafcde1">Delete Post</a>
The receiving script recreates the nonce using the same one-way hash algorithm and compares the result to the once received.
Managing Nonces Using a Library or Framework
There's seldom any reason for you to manage your nonces on your own as there are plenty of good libraries and frameworks that can help, including the OAuth 2.0 Authorization Framework, NonceUtil-PHP, and of course, WordPress.
Working with Nonces in NonceUtil-PHP
Working with these tools is really easy. Here's how to generate a nonce with one minute lifetime in NonceUtil-PHP:
$nonce = NonceUtil::generate('mySecretSaltString', 60);
Including a time limit is a good idea because it reduces the window of opportunity for a would-be attacker (or trigger-happy link/form button clicker) to try to utilize the link or Web form.
To validate the nonce, call the check() method, passing in your secret string and the nonce:
$valid = NonceUtil::check('mySecretSaltString', $nonce);
Check() returns true for success or false for failure.
Working with Nonces in WordPress
WordPress uses a similar mechanism, but its wp_nonce_url() function accepts a bare URL along with an "action" string, such as:
$nonce_enabled_url = wp_nonce_url( $bare_url, 'delete-post_'.$post->ID );
By default, wp_nonce_url() adds a field named "_wpnonce". You can specify a different name by supplying the optional 3rd argument to the function:
$nonce_enabled_url = wp_nonce_url( $bare_url, 'delete-post_'.$post->ID, 'nonce_enabled_delete_post_link' );
In addition, WordPress allows you to add a nonce to a form via the wp_nonce_field() function. All it needs is a string specifying the action. By default wp_nonce_field() generates two hidden fields, one whose value is the nonce and one whose value is the current URL (the referrer), and it echoes the result to stdout. For example, this call:
wp_nonce_field( 'delete-comment_'.$comment_id );
...might echo something like:
<input type="hidden" id="_wpnonce" name="_wpnonce" value="9c2fafcde1" /> <input type="hidden" name="_wp_http_referer" value="/wp-admin/edit-comments.php" />
Nonce Validation in WordPress
Nonce validation is shared amongst several methods, depending on the context.
Nonces passed in from an admin screen should be validated by check_admin_referer(). It accepts one argument of type string specifying the the action. For instance:
check_admin_referer( 'delete-comment_'.$comment_id );
Again, you can specify your own name by supplying an optional argument to the function:
check_admin_referer( 'delete-comment_'.$comment_id, 'nonce_enabled_delete_post_link' );
Nonces passed in using an Ajax request should be validated by check_ajax_referer():
check_ajax_referer( 'process-comment' );
In addition to the optional nonce name argument, check_ajax_referer() also supports other parameters to take some other action instead of terminating execution.
Finally, to verify a nonce passed in some other context, use the wp_verify_nonce() function. It accepts the nonce as well as the action string:
wp_verify_nonce( $_REQUEST['nonce_enabled_process_post_link'], 'process-comment'.$comment_id );
Having learned what nonces are and how they work, I hope that you may better appreciate their role in protecting against malicious or duplicate requests that could cause undesired permanent or irreversible changes to the web site and/or its underlying database. All the frameworks that we saw here today work much in the same way, so if you don't want to or can't use them, you can always roll your own by following their lead.