WordPress 2.0.3: Nonces

WordPress 2.0.3 has some security enhancements that a lot of people are wondering about, so here’s my attempt at explaining them.

Authentication: cookies are your backstage pass

When you sign into WordPress, you are granted a cookie… a little file that lives in your browser and acts as your “backstage pass” to the WordPress admin. This prevents unauthorized people from accessing your admin and doing bad things. They don’t have the cookie, so they’re stopped at the door by the bouncer. Your cookie is tied to your user account, which ties into the WordPress capabilities system which controls what things you can and can’t do in the admin. This is authentication: verifying that the person performing an admin action is authorized to do it.

Intention: the need to protect you from yourself

Say you’re logged in to your WordPress install. You can click links and submit forms that do things to your blog. Things like changing options, deleting posts, creating users, etc. What would happen if someone were to create a link or a form that points to your WordPress admin and attempts to do something malicious? Well, if an unauthorized person submits the form or clicks the link, nothing happens. They get rejected by the browser because they don’t have a login cookie. But what if you were tricked into clicking that link? Uh oh… the bouncer lets you in, and the action is performed. You have authority, but you lacked intention. You didn’t mean to click a link that would delete a post. You were tricked! In order to protect you from this, WordPress needs to make sure that you intend to do the things you do.

Intention: HTTP_REFERER is the old way

In the past, WordPress did the following: it verified that the page you were viewing before you initiated the action was a WordPress admin page. That is, you were already inside… the link or the form that you clicked wasn’t malicious; it was part of the WordPress admin. WordPress did this by checking the HTTP_REFERER value that your browser sent.

Intention: HTTP_REFERER shortcomings

HTTP_REFERER has problems. First, it can be spoofed by JavaScript in a certain popular browser (I’ll give you one guess). Second, some firewalls or proxies strip this information out. The spoofing means that it isn’t secure. The stripping of the referer means that some users won’t be able to perform actions in their WordPress admin. I grew tired of people complaining about not being able to use their WordPress admin, and wary of the security implications. I posted this message to the WP-Hackers list on April 17th, and a huge discussion ensued. I suggested an alternative method of verifying intention, and as of WordPress 2.0.3, this system has been implemented.

Intention: nonces are the way forward

A nonce is a number used once, and it is used for intention verification purposes in WordPress. Think of it as a password that changes each time it is used. WordPress’ implementation isn’t technically a nonce, because the electronic key only changes every 12 hours, and is valid for 24 hours (that is, the current key, and the penultimate key are valid), but it’s close enough. The idea is simple: we verify that user’s request is intentional by verifying that the request originates from within the WordPress admin. And we do that by providing a piece of information (a nonce) to them when that first page is requested. When the action is performed, the piece of information is passed along, and verified. Nonces can be locked down in many ways. They are unique to the WordPress install, to the WordPress user, to the action, to the object of the action, and to the time of the action (24 hour window). That means that if any of these things changes, the nonce is invalid. So if you (somehow) intercept a nonce being used by me, you would, first of all, only have 24 hours to use this key to attempt to trick me. And you’d only be able to use this key to trick me, on my blog, into doing a specific action to a specific item. So even if you got a nonce used to delete a post, the absolute worst case scenario is that you might be able to trick me into deleting that specific post. The nonce is useless for any other purpose.

Nonces: use them in your plugins!

Plugin authors, listen up. In order to prevent the backwards-compatibility “Are you sure?” dialog from coming up when HTTP_REFERER-agnostic users interact with your plugins (especially options pages), you need to add nonce capabilities to your plugins. Don’t worry, it’s way easy.

<form> nonce protection

To protect your <form> with a nonce, simply use the wp_nonce_field() function within the <form> (I’d do it right after the opening tag.) For backwards compatibility, use function_exists() to execute the code conditionally. The string you pass to the function should be unique to your plugin. Use the following convention: plugin-name-action_object So, if my plugin is called “cool plugin” and the action the form does is “update options” and the object is “advanced options,” I’d do cool-plugin-update-options_advanced. The “object” part isn’t required, but if you have multiple forms, protect each one with a different object for the highest level of protection.

<form ...>
if ( function_exists('wp_nonce_field') ) 
	wp_nonce_field('plugin-name-action_' . $your_object); 

Link nonce protection

If you’re performing actions based on the clicking of links, you can add a nonce to your links using wp_nonce_url() which takes two parameters. The first is the URL of the link, the second is your nonce key. Note the use of function_exists() for backwards compatability:

$link = 'your-url.php';
$link = ( function_exists('wp_nonce_url') ) ? wp_nonce_url($link, 'plugin-name-action_' . $your_object) : $link;

<a href="<?php echo $link; ?>">link</a>

Nonce verification

On the backend, before performing the action protected by the nonce, simply call this:

<?php check_admin_referer('plugin-name-action_' . $your_object); ?>

Feedback and other resources

Please let me know if any of this information (especially regarding plugin nonce implementation) is incorrect and I’ll update it. You should also give Owen’s post on WordPress’ nonce implementation a read.

177 thoughts on “WordPress 2.0.3: Nonces

  1. Blathering:

    The format for the nonce action names you describe is worth following: verb-noun_object (like delete-post_100 or cool-plugin-update-options_advanced). It may seem pointless now, but future versions of WordPress may (no promises) parse the action name to make the “Are You Sure” message more informative.

    Perhaps plugin:verb-noun_object should be encouraged (cool-plugin:update-options_advanced). However, without anything even resembling a guarantee that the action names will be processed like this, it’s not worth starting a campaign.

  2. Excellent post Mark, but there is one more thing:

    Correct me if I’m wrong but,

    So even if you got a nonce used to delete a post, the absolute worst case scenario is that you might be able to trick me into deleting that specific post. The nonce is useless for any other purpose.

    Isn’t the only way you could get a nonce be if you carried out an action? I mean, in order to retrieve the nonce key in the first place, you’d have to have already had deleted the post in question by your intention, and as such, the best one can do would be to trick you into deleting that post again – except it’s already gone?

    Not sure if that made too much sense….

  3. CG,
    The nonce is provided in the previous load, during which the action might or might not take place. For instance, when you open up a post for editing, you get the deletion nonce for that post, so if it was intercepted downstream, it could be used, even when you didn’t intend to use it. But consider that if people are intercepting your Internet traffic, they’d be better off just grabbing your authentication cookie.

    The different ways that a hacker might get their hands on a nonce might not be known. But in the event that it does, somehow, happen… the effects will be limited to a specific blog, a specific user, a specific action, a specific object, and a specific time period. And also, keep in mind that getting a nonce is only half of the puzzle, if you’re a hacker… you also need to mount a CSF attack whereby you trick that specific user on that specific blog into visiting your malicious link/form. And you only have 12 to 24 hours in which to do so.

    The prize generally sucks, the attack must be manual, and it relies on social engineering to succeed. And as of right now, there isn’t even a known way to intercept a nonce.

  4. Pingback: kakoky.net
  5. Pingback: due chiacchiere
  6. Pingback: Stickiing around
  7. This is totally not working for me. I have the wp_nonce_field() function working correctly in my , looking at the source code. The problem is when I click the Submit button.

    Presumably, if the nonce is working correctly, the action should be performed without any further user intervention. What I get instead is the WP admin header, followed by this message:

    Warning: Cannot modify header information - headers already sent by (output started at C:\Documents and Settings\joepan\My Documents\Developer\wpdev\wp-admin\admin-header.php:16) in C:\Documents and Settings\joepan\My Documents\Developer\wpdev\wp-includes\functions.php on line 1219

    After that, there is the “Are you sure you want to do this?” confirmation message.

    The code for my action handling currently looks like this:

    // Clear logs if told to
    if ($_POST['lumberjack_logviewer_action'] == 'Clear logs') {
    $query = "TRUNCATE TABLE `$lumberjack_logs_table`";

    What am I not doing correctly? This is in WP 2.1.

  8. Part of my code got cut off there, because of HTML markup, but the code excerpt should be enough and I assure you the problem has nothing to do with parsing errors or any other such thing. It works fine without the check_admin_referer() function call.

  9. Can someone help me out here? I was expecting that if the ‘unique string’ passed from the form to the processing of that form was different then the update would somehow be stopped for a check to be made. But no matter what I pass in either function – no identical characters whatsoever – my update proceeds untouched every time. Is that right?

  10. Sai Krishna says:

    Hi Mark,
    Is it necessary that to create wp_nonce_field when we are creating a plugin for administrator or is it purely optional ? I’m trying to use wp_redirect, which results always is headers already sent refering to admin-header.php and pluggable-functions.php

  11. Greg says:

    “This is authentication: verifying that the person performing an admin action is authorized to do it”

    IMHO, this is authorization. Authentication is about making sure you are the one you claim to be.

    My .02€

  12. Hi Mark,

    I looked around google and the wp docs and forums for information regarding nonce in theme options pages, but I only seem to find information regarding nonce in plugin nonce pages.

    I have added the question to the wp forum, but I guess nobody knows the answer or don’t care, as nobody has replied yet, so I was wondering if you could shed some light on the subject. Is it required for security and if so, do you know of any tutorials regarding this?


  13. I’ve just started developing (reading a lot about WP plugin development, best practices and Twitter API) a Twitter plugin. This post is one of the best I’ve read pointing out security issues!

    Thank you!

  14. Brenton says:

    I hate to nit pick, but its the Standards editor in me. In the realm of software security the terms authentication and authorization have specific meanings and are not interchangable (as your article suggests in the first paragraph). If you weren’t providing a widely quoted introduction to WordPress security and instead were just mentioning this in passing, then I wouldn’t bring it up. But since you have the attentive ears of people who want to learn, then I feel compelled to correct the mistakes so that others don’t learn mistakes.

    Authentication is the process of proving your identity. This is typically done with providing some secret (e.g. a password) that should only be known by the individual in question. In well secured systems, not even the system knows this secret. Unix, for example saves a hash of the password so its authentication system really only compares a hash of the password supplied with what it has on record.

    Authorization is the process of determining if you have the permissions to request what you have asked the system to do. For example, being able to update the settings in WordPress will require WordPress first determine what priviledges are required for this action and then determine if you have those priviledges (this is authorization).

    I’ll stop here because this reply is getting too long, but its important to get these fundamental concepts straight so that you (and your readers) are using the accepted nomenclature of software security.

  15. Can nonces be reused? I know they expire after 24 hrs, but if I use it once, can someone come back to my computer and use it again, with a form repost or something of this nature?

  16. I think the nonce could be pretty handy for me. I’m suffering from an awful lot of spamming at the moment on my wordpress blogs.

    Could you do a followup with some infor for us newbies?


  17. PHP coding is new to me but I’ve had experience in VB and C++ so I thought the transition would be easy. It wasn’t and isn’t lol. For some reason PHP is just different enough to be a pain.

  18. У нас даже дешевая парфюмерия имеет великолепное качество, за которым следят наши менеджеры и лаборатории. Мы производим отбор профессиональную косметику делая упор на финансовую состоятельность всех прослоек населения. Милые девушки останутся удовлетворены нашей парфюмерией . Качественная парфюмериея гарантированно прибудет к вам в течении нескольких дней с момента заказа через наш Интернет магазин. Для постоянных клиентов и парикмахерских мы можем предложить профессиональную косметику со скидкой.

  19. The root of your writing while sounding agreeable in the beginning, did not really sit perfectly with me personally after some time. Someplace within the sentences you managed to make me a believer unfortunately only for a while. I still have got a problem with your jumps in assumptions and one might do well to fill in all those breaks. If you actually can accomplish that, I could certainly end up being fascinated

  20. Today, considering the fast way of life that everyone is having, credit cards get this amazing demand throughout the economy. Persons throughout every arena are using the credit card and people who aren’t using the card have made arrangements to apply for just one. Thanks for giving your ideas on credit cards.

  21. One more issue is that video games usually are serious naturally with the major focus on finding out rather than amusement. Although, it has an entertainment factor to keep your sons or daughters engaged, just about every game is often designed to work with a specific group of skills or course, such as math concepts or research. Thanks for your article.

  22. marketing howell, mi says:

    There are actually a whole lot of details like that to take into consideration. That is a great point to bring up. I offer the thoughts above as normal inspiration however clearly there are questions like the one you deliver up the place a very powerful thing can be working in trustworthy good faith. I don?t know if best practices have emerged around things like that, however I am sure that your job is clearly recognized as a good game. Both girls and boys feel the impact of just a second’s pleasure, for the remainder of their lives.

  23. I’d must test with you here. Which is not something I usually do! I enjoy studying a put up that will make individuals think. Additionally, thanks for allowing me to remark!

  24. Pingback: | WP Roots
  25. @ Mark great article on wp nonces.

    @ Brenton Thanks for sharing your thoughts, I’m a new developer and I think you are spot on about wanting to clarify the fundamentals when it comes to security concepts. It would be awesome if WordPress used hash strings to really lock things down.
    Mark you forgot to enable Akismet! :P

  26. greg says:

    I am using this, creating a unique $name for each action in my admin. Should the $action var be the name of the action the form calls, or can it be anything?

    • Ciantic says:

      Notable thing is that nonce is not unique! Consider this: wp_create_nonce(‘something’) then next nonce within 0-12 hours using wp_create_nonce(‘something’) is same for given user and wordpress of course. It cannot be used for preventing duplicate add entries (clicking submit too many times where possible) either because of this.

      I’m not sure what are you up to, but nonce are meant for only simple validation of intent, not for real unique ID’s e.g. prize number ID underneath coke bottles.

  27. I actually using nonces along with akismet on one of my new plugin… I initially thought of using the image captcha but nonces suddenly pop on my head.

Comments are closed.