WordPress caching and nonce lifespan

on June 18, 2012 in WordPress with 9 comments by

A security feature available in WordPress is a “nonce”. Generally, a “nonce” is a token that can only be used once and are often used to prevent unauthorised people  from submitting data on behalf of another person. Let’s simplify that:

  • Person A is given nonce “A”
  • Person B is given nonce “B”
  • Person B attempts to submit data to the server on behalf of person A
  • The server reads the submitted data from person B as “Person A with nonce  ‘B’ is submitting data”. Knowing that Person A does not have nonce ‘B’, it ignores/denies the submitted data.

WordPress differs by giving it a lifespan and allowing the nonce to be used more than once within that lifespan by the same person. And by the ‘same person’ it is meant a logged in WordPress user, or an anonymous user (visitor not logged in).

The benefit is that the server does not need to keep track what nonce it has given to any particular user. It just needs to know the user returning the nonce and the current time; based on that information, it creates another nonce and checks if it matches the one returned.

Using time as part of a nonce

As time varies, WordPress needs to allow for a nonce generated at 10:01 AM to be valid at 10:02 AM. It does this by using a time “tick” instead of the actual time, which is generated in two steps:

  1. First divide the lifespan of a nonce, in seconds, by two
  2. Divide the Unix timestamp by the above value, and round it up using ceil()

By default, the lifespan is 86400 seconds, or 24 hours (and can be adjusted with the nonce_life filter). Half this, 12 hours, is 43200.

So at 10:01 AM on 18/06/2012, the Unix timestamp is 1340031660. Dividing that by 43200, rounded we get 31019. A minute later (10:02 AM), the timestamp is 1340031720. Dividing and rounding, we also end up with 31019. In fact, for the first 12 hours of the day this value will be the resulting “tick”.

The reason WordPress divides the timespan in two, is that it can determine if a nonce was created in the first or second half of its full lifespan, simply by incrementing a “tick” by one.

Nonce time caveat

Based on a 24-hour lifespan, a “tick” as calculated above is the same for each 12-hour span of a day. At 07:45 AM the “tick” is the same as 9:30 AM and 11:59 AM. But it will be one less than a “tick” created at 12:01 PM (a new 12-hour span within the day) or 15:30 PM.

Because of this, a WordPress nonce is not valid for exactly 24-hours from the moment that it was created, but up to 24 hours, depending how far into a 12-hour period a nonce was created.

Nonces and WordPress Cache

Nonces can also be used on the “public” side of WordPress, and can help reduce abuse of data submissions. My WordPress plugins use this, as do some others like Contact Form 7.

As a nonce is often added as a (hidden) form element or using JavaScript, this means that it will also end up being cached by a WordPress plugin such as WP Super Cache or W3 Total Cache. This can cause some issues with nonce verification.

The main issue is how long a page is cached and how most caching plugins determine the age of a cached page. As mentioned earlier, a nonce “tick” is not valid for exactly 24 hours. On the other hand, the age of a cached page is determined from when it was first cached. So if a page is cached for 24 hours (or more), it allows the possibility for a nonce to expire and thus become invalid.

For example: a page is cached at 10:01 AM on 18/06/2012. The “tick” of used for the nonce at this time was 31019. 24 hours from that time, at 10:01 AM on 19/06/2012, the server calculates a “tick” to be 31021. But as the cached nonce was based on a “tick” of 31019, any attempt to use it for data submission would fail.

To avoid this, a page should be cached for at most 12 hours, provided the life-span for a nonce has not been changed from its default 24 hours. The author of WP Super Cache also provides an alternative solution, though that may not be a suitable solution in all cases (ie., in AJAX that uses nonce on all pages).

Cache garbage collection

In WP Super Cache’s case, by default a cached page becomes stale after an hour, which is well less than the 12 hours. But for the stale page to be refreshed using its Garbage Collection feature (see the Advanced tab), the collection has to be done in time as well. For instance, if the cached page has become stale after an hour, but garbage collection is done every 24 hours, the stale page will still be used for up to 23 hours.

This is further complicated because the WordPress Cron (the scheduler for performing tasks) usually checks its schedule whenever a visitor accesses the website. On low-traffic websites, this could give large variations between the scheduled time versus actual time a task is performed (such as the garbage collection). In these instances, it would make better sense to use a UNIX Cron Job to call wp-cron.php, or to reduce the garbage collection time as much as possible.

Tags: ,

9 comments

  1. posted on Jan 14, 2017 at 1:10 PM  |  reply

    […] « WordPress caching and nonce lifespan ». myatus. https://myatus.com/p/wordpress-caching-and-nonce-lifespan/ […]

  2. Rajendra Singh
    posted on Jun 30, 2016 at 12:58 AM  |  reply

    Good tutorial. It cleared my confusion. Thanks…

  3. Will Brand
    posted on Mar 02, 2016 at 4:45 PM  |  reply

    Thanks for this explanation; ended up being a lifesaver.

    If anyone’s running into this issue with W3TC, try using WP-CLI to set up a cronjob that runs “wp w3-total-cache flush” every hours.

  4. posted on Aug 28, 2014 at 3:38 PM  |  reply

    So I pulled up a form logged in and the nonce was precisely the same for a logged out user. How does this happen? I’m using the contact 7 plugin.

    • Myatu
      posted on Sep 03, 2014 at 9:10 PM  |  reply

      That sounds like the page is being cached.

  5. tkane2000
    posted on Sep 16, 2013 at 8:34 PM  |  reply

    hmm, I must be missing something here! The nonce is created based on time, but user A will have a different nonce than user B. Therefore, it can’t be created only with time, or user A & B would always have the same nonce.

    Further more, if user A and user B have different nonces, then they can’t be cached on the server side (or on the edge) unless the nonce is used as the cache key. Otherwise, user A could get the nonce for user B in a hidden field, for example, if user B visited the page first after the last cache clear.

    So, if I’m correct about that (which I’m probably no) the lifespan of your cache wouldn’t make a difference. Is this correct or am I missing something?

    Thanks!

    • posted on Sep 16, 2013 at 9:09 PM  |  reply

      The nonce is created based on the logged in user – if any – and the time. If there is no user logged in, then the nonce that the anonymous person A and B receive are indeed the same.

      Most WordPress caching plugins will not cache pages when a user is logged in, but will if there’s an anonymous visitor. As noted, the nonce for anonymous visitors will be the same – but only valid for the time that WordPress specifies, which may be less than the caching time.

      • tkane2000
        posted on Sep 16, 2013 at 9:43 PM  |  reply

        Awesome, thanks for the clarification! I’ve been trying to figure out if there’s a way to use edge server caching on a post page that has Discussions enabled. (not looking good)

  6. posted on Mar 01, 2013 at 11:04 PM  |  reply

    Thanks for the thorough explanation!

Join the discussion

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