Nonces are one of those things that, hopefully, all WordPress developers know they need, but there is still a lot of confusion about. Maybe it’s beacuse “nonce” means a number used once and a WordPress nonce is not a number and it can be used. So it’s closer to a nonce than a nonce word, but it can be used multiple times, but I digress.
The point here isn’t semantics, it’s to discuss some problems nonces present. I run into problems with Caldera Forms + caching plugins that are set with infinite cache lengths as this causes our nonce validation to fail.
This article isn’t about setting up caching plugins or services or which one is best. It’s about understanding one of the gotachas with many caching plugins: caching nonces.
I want to talk a bit about what nonces are, why we use them and what can go wrong. I’ll keep it brief, as I’ve written a more detailed article on nonces for Torque already.
What Is A Nonce?
As I said earlier, “nonce” means “a number used once.” For example, most payment processors, like Stripe issue a one time use token, which is a mix of numbers and letters, for creating a payment. They call it a token, but same concept, technically a nonce word. You request the token with a public API key and then complete the payment with the token and the secret API key.
Nonces are not a security feature by themselves since they become public once printed to the page. Also, in WordPress, nonces can be used more than once.
Nonces help prevent cross-site request forgery, beacuse they can be used to prevent requests from external sources form mimicking intended HTTP request. Also, nonces make up part of your strategy to prevent XSS attacks since they help verify that the request is coming from the intended user.
As I said in the last section, nonces can be used more than once. They remain valid for a set period of time. By default this is 12 hours, but can be changed with the nonce_life filter. This design decision means that WordPress doesn’t have to keep a record of nonces created and if they have been used. That probably would have required a new database table.
This is important to keep in mind. As are the other ingredients of a nonce. For example, one of the components that goes into a nonce is user ID, or 0 if the user is not logged in. This prevents nonces from non-logged in users from validating when a user is logged in. This by the way is why you should always send the REST API nonce on every request. If you don’t other nonces might not validate properly.
Forms, Caching And Nonces
Every form in WordPress should use a nonce to prevent cross-site forgery requests. All forms provided by WordPress core do. This includes comment forms. Also, your contact form should. We use a nonce in Caldera Forms.
In the last section I mentioned that nonces can be reused for a period of time, normally up to twelve hours. This is good beacuse it means that you can cache the content of a page with a from and the form will still work, for up to twelve hours.
The “up to twelve hours” part is the rub.
The idea behind a static HTML cache is that you only generate the page output once, and serve the same thing, which should be identical to all other visitors. This makes sense as it prevents running the same database queries and running the same PHP scripts to do the same thing over and over again.
Great, but if you have a nonce in your content, it could get expire and prevent your forms from working. Obviously this is a problem we face with Caldera Forms, when it is used with caching plugins or proxies like CloudFlare. This is also one of the reasons people have moved away from native commenting in WordPress.
What To Do?
One thing not to do is to re-generate nonces from other plugins, before they can be validated. This bypasses the problem, but defeats the purpose of the nonce. I’ve seen plugins do it though 🙁
It’s common practice to bypass the cache for logged in users. One reason is that the content may be unique to the user. The other is that nonces are unique to the user and can’t be shared.
The other thing you really should do is keep your cache times short. Definitely less than 12 hours, but probably even shorter. Also, relying on a non-PHP solution like Varnish or nGinx as a reverse proxy is preferable, but you still need to make sure your cache time is short enough.
By the way, if you’re wondering which caching plugin I recommend, I don’t use one. None of my sites receive thousands of concurrent views. The Caldera Forms site is I’m dealing with few thousand page views a day, not a time and we have it on a small AWS VPS that can handle that easily, especially with all of the assets coming from a CDN.
If they did, I would probably use Varnish and/or nGinx as a reverse-proxy over a plugin. I do use Redis as a persistent object cache whenever possible. A good WordPress host should provide a static HTML cache, powered by a server appliance, with a short cache length.
Nonces Are Important, But Don’t Get Cute
Nonces are important, if you do WordPress development, make sure you read the WordPress developer handbook section on nonces. If you have questions, ask in the comments. Also, be careful not to get cute with nonces, and always use wp_verify_nonce() to verify nonces to avoid issues like I discussed in this post.