Improving security in WordPress plugins using Nonces

Using a nonce (number used once)  is the best way to protect your plugin against a cross-site request forgery (CSRF) hacker-attack. Nonces are used on requests (saving options in admin, Ajax requests,  performing an action etc) and prevent unauthorized access by providing a secret 'key' and checking it each time the code is used.

Nonces in WordPress

Nonces work in the following way:

  1. First you generate a nonce with a unique identifier
  2. You pass the nonce along other query data (link or form) to you script
  3. You verify the nonce before doing anything else

In order to create a nonce you can use wp_create_nonce() function.

$nonce= wp_create_nonce  ('my-nonce');

Next, pass the value of $nonce as a parameter in your request. For example:

<a href="myplugin.php?_wpnonce=<?php echo $nonce ?>">

You can use wp_verify_nonce() function to check the nonce before you perform any other action in the plugin.

$nonce=$_REQUEST['_wpnonce'];

if (! wp_verify_nonce($nonce, 'my-nonce') ) die("Security check");

And that's all! If you thought it can't be any easier than this you'd be wrong.

Using nonce functions

WordPress provides couple of functions to simplify the usage of nonces even more.

For your forms you can use wp_nonce_field() which will output a hidden field with a nonce. Place the function somewhere inside your form.  For example:

<form action=... >

<?php wp_nonce_field('my-nonce'); ?>

...

</form>

If you want to add a nonce to a link, you can use wp_nonce_url() function.

For example:

<a href="<?php wp_nonce_url($url, 'my-nonce'); ?>">

If you are using the plugin on administration pages you can then use check_admin_referer() function to check the nonce. For example:

check_admin_referer( 'my-nonce');

It will automatically extract the nonce from query parameters (_wpnonce) and verify it.

Nonce and Ajax scripts

it's easy to use nonce in your Ajax scripts.  First create a nonce using wp_create_nonce().

$nonce= wp_create_nonce  ('my-nonce');

Then pass the nonce as _ajax_nonce parameter somewhere in your Ajax call:

$("#text").load(".../ajax_response.php?_ajax_nonce=<?php echo $nonce ?>");

To check the nonce in ajax_response.php use check_ajax_referer() function:

check_ajax_referer('my-nonce');

Here is another example (taken from Live Blogroll) plugin:

$nonce = wp_create_nonce( 'wp-live-blogroll' );
...
jQuery.ajax({
type: "GET",
url: '<?php echo $wp_live_blogroll_plugin_url ?>/wp-live-blogroll-ajax.php',
timeout: 3000,
data: {
link_url: this.href,
_ajax_nonce: '<?php echo $nonce ?>'
},
success: function(msg) {
jQuery('#lb_popup').html(msg);
jQuery('#lb_popup').fadeIn(300);
},
error: function(msg) {
jQuery('#lb_popup').html('Error: ' + msg.responseText);
}
})

Receiving file:

function WPLiveRoll_HandleAjax($link_url)
{
// check security
check_ajax_referer( "wp-live-blogroll" );

Including nonces should not take more than 5 minutes for most plugins, and it is something all plugin authors (including me!) should work on.


More like this:


Posted in: WordPress
TAGS:, , , , , , , , , , , , , , , ,
Both comments and trackbacks are currently closed.

22 Comments

  1. joomlaserviceprovide
    Feb 8th, 2012

    Greetings. We are pleased to announce the release of wSecure. wSecure hides your WordPress admin URL with a special key so that only you can access. The problem with WordPress is that anyone can tell if your site is WordPress by simply typing in the default URL to the administration area (i.e. http://www.yoursite.com/wp-admin). wSecure helps you hide the fact that your website is built with Worpdress from prying eyes.

  2. GB
    Oct 4th, 2011

    Using this - Does the action variable need to match the name of the action in the form, or can it be anything?

    • J.D. Grimes
      May 28th, 2013

      It can be anything. But matching the action in the form might be a simple way to keep them organized. It's entirely up to you.

  3. Rumpelstintskin
    Mar 29th, 2011

    All reserves expressed about the mechanism proposed by Vladimir have to do with nonces being valid for 24 hours. Is that imperative by design? Why not real nonces, that is, once a request is received in the server with that token, is never to be used nor seen again? Furthermore, is never to be valid again in combination with the session where it was produced, regardless of wheter it was consumed or not. I am probably being naive here, since I just jumped on the topic, but I need to understand if this approach might work, then I would adapt it to Java.

  4. nierdz
    Feb 21st, 2011

    Hi,
    I tried to implement this in an ajax plugin but i get Call to undefined function wp_create_nonce().
    Is there a way to deal with that ?
    More precision, the plugin is just an ajax widget and I use OO by extending the WP_Widget class.

  5. Jan 19th, 2011

    Like naomi asked, I am using wp 3.01 or whatever. Does this apply to my site?

  6. Nov 25th, 2010

    Thank you..
    exactly what i wanted...
    Thanks again...

  7. Jul 2nd, 2010

    I'm using wp_nonce_url($url, 'my-nonce') and it's converting my $URL which includes a few variables into &

    So...
    http://www.domain.com/?var1=7&var2=12
    becomes
    http://www.domain.com/?var1=7&var2=12_&wpnonce=48ea26a9c3

    Any way around this, since this makes "var2" become "amp;var2"

  8. RC
    Apr 3rd, 2010

    Vladimir, you are the man! I purchased your book on building plugins and it has been worth the money.

  9. Manoj
    Feb 25th, 2010

    Thanks, This is what i m looking for.

  10. Brenton
    Nov 18th, 2009

    I've implemented nonces for the Admin pages of my plugin, but after thinking about this for a while I'm of the opinion that its really not an adequate solution. Specifically, there are two short comings with this whole approach:
    1. Its NOT a number used once. Its a number that can be used as many times as you want in 24 hours. Does this make a difference? Yes! The whole problem thats trying to be solved is someone hijacking a session (originally, this was just the cookie, but now its the nonce as well). A 24hr window of opportunity is ridiculous. A competent hacker would need about 2minutes in your WordPress installation (if they were organized) to setup a back door: probably less if they had rehearsed it. Hence my biggest gripe with this types of solutions: a false sense of security. Nonces only marginally increase your protection, but if you read the way people rave about this principle you would think that all threats have been eliminated.
    2. Its intrusive. Its a royal pain in the a$$ to mutilate your URLs with this stuff - and even worse when it doesn't provide effective security. At least cookies are transparent to URLs! I can't count the number of times clients of mine have said "our theme doesn't use widgets so we want to embed your plugin-generated URLs directly in our theme". Sounds like a reasonable request. But wait! I need to tell them that those URLs contains nonces and hence you need to fetch them a-new everytime you want to display them. In effect, they're dynamic URLs. That requires them to write PHP code; and over 50% of my clients aren't PHP programmers. My point is that this approach takes away some existing flexibility but doesn't really improve the security of the system in return.
    Now that I've got that out, I'm going to propose an alternative, just so I won't be accused of being a whiner.
    Go back to the threat and work within the existing constraints.
    The threat is session hijacking. Existing constraints are static URLs. Proposals:
    1. augment session authentication (i.e. cookies) with IP address filtering. Have WordPress not only require a valid cookie but a cookie that came from the same IP address it was issued to and was received from. I know IP addresses can be spoofed but nonce sessions can be spoofed too with far greater ease. At least with this approach you don't have to mangle your URLs.
    2. Update the cookie value on every request. Although this sounds good in theory, in practice it would probably cause a lot of false-positive lock-outs which would require the user to log back in again. And fundamentally, it actually doesn't resolve the problem: its just reduces the window of opportunity to an incredibly short time. If a hacker were fast enough (i.e. submitted the next page as you before you did) then they would be let in and you would be locked out.
    As you can see, it appears that there might not be an effective solution at this level. It may simply be that WordPress does the best it can (using cookies and source IP address) and leave it up to other technologies to provide a comprehensive security solution: e.g. SSL to stop anyone else from eavesdropping on the data sent back and forth. Perhaps even having WordPress run its admin functions on a restricted IP port which requires SSL client side authentication to establish the HTTPS connection. At some point you need to ask yourself, what is the value of the website (asset) I'm protecting? what is the likely investment a typical hacker will make to gain control of that asset?, and is my security system's cost inline with these values?

    • Nov 18th, 2009

      How do you propose the hacker would hijack a session that uses nonces?

      • Brenton
        Nov 23rd, 2009

        The method of exploiting a nonce is not the issue. But since your reply implies (at least to me) that the absence of an exploit is proof that nonces are secure, I will elaborate.

        Nonce values are transmitted with each HTTP request along with the cookie. Thus one method of exploit would be to monitor the HTTP traffic between a privileged user (e.g. administrator) and the WordPress app to observe the nonce and cookie values. Since the nonce is not a number used once but several times, the hacker can reuse a previously observed nonce provided that it hasn't yet expired (default 24hrs). It is true that the nonce will only be useful for a particular page, so the hacker would need to find an instance of the admin visiting the desired administration page. As WordPress doesn't have that many admin pages, this is not problem. With this information, the hacker then only needs to craft their own HTTP message using the same cookie and nonce values. This part is simple and since WordPress doesn't associate cookies (or nonces) with a particular TCP connection, the hacker does not need to be concerned with spoofing the client IP address. WordPress would accept this crafted request because it contains a valid cookie and a nonce value that is valid for that page eventhough it originates from the hacker. Methods to mine such HTTP traffic include monitoring unsecured shared networks (e.g. wifi in coffee shops) and accessing webserver logs. Thus, since exploits exists and the effort and technology required are not infeasible this demonstrates that the nonce approach is not completely secure. Furthermore, and I made this point in the last post, since the method of exploit is not any different than that used to hijack a cookie-based session, the nonce approach only improves security marginally yet isn't transparent and is (IMHO) inconvenient (viz. mangled, dynamic URLs). Based on this analysis, I would suggest that a better approach would use technology whose vulnerabilities are not coincident with those of cookie-based session hijacking.

        • Nov 24th, 2009

          If the hacker can monitor HTTP traffic between administrator and WordPress, woudln't he just use the username/password and login as an admin?

          • Brenton
            Nov 25th, 2009

            I thought this would happen if I answered your question: the thread would wander off topic.

            The main issue is that nonces don't add much more security that what is already provided by cookies, but come at a high price in terms of mangled/dynamic URLs.

            My main point is that I think that the need for such increased security is marginal and that the nonce approach only introduces incrementally better security but at too high a price (IMHO).

    • Matthew
      Nov 23rd, 2009

      It seems that you are not implementing sufficiently precise action descriptions for your nonces. If a hypothetical attacker discovers one of your nonces in the 24-hour valid period, they should only be able to perform a very limited, specific action.

  11. Tom
    Oct 10th, 2009

    Someone had to point out that for us UK readers "nonce" is an extremely widely used and understood slang for a paedophile, which makes virtually every statement above extremely "humorous". Sorry to be childish, but I assure you it's true. http://www.google.es/search?hl=en&rlz=1B3GGGL_en-GBES329ES329&q=nonce+uk&btnG=Search

    • Oct 12th, 2009

      Well luckily it wasn't me who came up with the expression :)

  12. Jul 19th, 2009

    Thanks a lot for this!

  13. Jul 14th, 2009

    Exactly what I was looking for! Thanks.

  14. Jul 9th, 2009

    thanks, it's just what i'm looking for.

  15. Mar 24th, 2009

    Does this still reign true for WordPress 2.7 and above?

  • ManageWP