One of the topics I discuss regularly with developers it that of access. When writing any code, we must always consider who should have access to it. Not in the ‘who can look at my code?’ aspect, but that of who can run the code.

This happens a lot with plugins and themes when people create their own settings pages. While I’m the first to admit that the settings API in WordPress is a bag of wet hair that makes little logical sense, using it gives you access to a lot of built in security settings, such as nonces.

But as I often tell people, a nonce is not bulletproof security. We cannot rely on nonces for authorization purposes.

What is a Nonce?

A nonce is a word or expression coined for or used on one occasion. But in security, a nonce is an arbitrary number or phrase that may only be used once. Due to it’s similarity to a nonce word, it reuses the name. In WordPress, it’s a pseudo-random number created on the click of (say) a save button, to ensure that someone had to press the button in order to run the function.

For example. If your settings page has a nonce, then the nonce is generated on click and passed to the function(s) that validate and sanitize and save. If the nonce doesn’t check out, then WordPress knows someone didn’t press a button, and it won’t run the save. This prevents someone from just sending raw data at your code.

Why isn’t that enough?

With just a nonce, anyone who has access to the page can save data. This is okay when you think about something like a comment form or a contact form. Those are things that need to be accessible by non logged in users, right? What about the WordPress General settings page? The one that lets you change the URL of the website? Right. You only want that to be accessible to admins. Imagine if all logged in users could change that one. Yikes!

In order to protect those pages, you have to consider who should have access to your code.

  1. Are the users logged in or out?
  2. What user permissions should be required?
  3. How much damage can be caused if the data is changed?

That’s it. That’s all you have to ask. If it’s a contact form, then a nonce is all you need. If it’s a site definition change, then you may want to restrict it to admins or editors only.

The Settings API

When you use the settings API, some of this is made pretty straightforward for you:

add_action( 'admin_menu', 'my_plugin_admin_menu' );
function my_plugin_admin_menu() {
    add_options_page( 'My Plugin', 'My Plugin', 'manage_options', 'my-plugin', 'my_options_page' );
}

In that example, the third value for the options page is manage_options which means anyone who can manage site options (i.e. administrators) can access the settings page.

The problem you run into is if you want a page to do double duty. What if you want everyone to see a page, but only admins can access the settings part? That’s when you need to use current_user_can() to wrap around your code. Just check if a user can do a thing, and then let them in. Or not.

What Permissions are Best?

In general, you should give admins access to everything, and after that, give people as little access as possible. While it may be annoying that an editor can’t, say, flush the cache, do they really need to? You have to measure the computational expense of what’s happening before you give access to anyone. It’s not just “Who should do a thing?” but “What are the consequences of the thing?”

Look at the cache again. Flushing a cache, emptying it, is easy. But it takes time and server energy to rebuild. By deleting it, you force your server to rebuild everything, and that will slow your site down. An admin, who has access to delete plugins and themes, should be aware of that. An editor, who edits posts and menus, may not. And while some editors might, will all?

This gets harder when you write your code for public use. You have to make hard decisions to protect the majority of users.

Be as prudent as possible. Restrict as much as possible. It’s safer.

Reader Interactions

%d bloggers like this: