WordPress caching and nonce lifespan
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:
- First divide the lifespan of a nonce, in seconds, by two
- 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.
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.