Are your plugins secure?
Published October 11th, 2012 under Plugins
I originally authored this post on WP Realm, but I moved it back here after that website folded.
WordPress has an irritatingly bad reputation for security. This is mostly due to misinformation and partly due to WordPress taking the rap for flawed security either at server level, or at the theme/plugin level. Server security issues can be reduced by using a well respected webhost such as HostGator or WP Engine. Theme and plugin security can be much harder if you are unable to security audit the code you are using. A quick search through the WordPress plugin repository by a trained eye can show up a scary proportion of plugins with security flaws. Unfortunately, unless you understand how security attacks occur and what type of code causes security flaws there is no way to know if a plugin is usable or not.
Unfortunately, providing a comprehensive lesson on web security in a single blog post is impossible. The subject of security is broad and new ways to exploit code are constantly being developed. To stay on top of the world of internet security is a very tricky task, but we can at learn some basic techniques for analysing code to determine if any major flaws exist. This blog post is intended to teach you how to see some simple security flaws. If you see these types of flaws in a plugin or theme, you should steer well clear of it.
User submitted data
The most common attack vector for hacking WordPress via plugins and themes is cross site scripting (XSS). This form of attack involves injecting JavaScript into a site. To do this, users need to submit data to your site. If users can never submit data to your site, then your site should be considerably less vulnerable to XSS. A site with no user submitted content would unfortunately be a very boring website.
WordPress core internally uses aggressive data sanitisation on all data submitted by users. The only user level at which WordPress takes a more relaxed approach is for administrators (or super admins on multisite) since those users are considered “trusted”. If a member of the public submits a blog comment, WordPress parses the text input through the wp_kses() filter to remove all potentially nasty code. Plugins and themes should use the same aggressive approach to data sanitisation, but unfortunately this is often not the case.
Based on this, it is clear that any data which is submitted by a user must be throughly sanitised to ensure that no nasty code gets through. Unfortunately, finding that un-sanitised data is very difficult.
Finding un-sanitised inputs
The four most common forms of un-sanitised inputs found in WordPress plugins/themes are raw query strings, post requests and server variables. It is critically important to ensure that any of these data inputs are scrubbed clean of all potentially nasty code before doing anything with them. If a value to be a string of text with no HTML, then all HTML should be stripped out, if the value is expected to be a number, then a check should be in place to ensure that the value is indeed numeric and doesn’t contain any malicious attack code. Never allow any data to interact with a plugin or theme which doesn’t match the format expected.
Query strings
$_GET and $_REQUEST variables can be used to access data from query strings in URLs. If a plugin outputs the contents of a $_GET variable onto the page, they will have the ability to send other users to a page which may potentially execute JavaScript included via a query string.
A prime example of this type of security attack is in themes which display search strings back to the user who performed the search. The following is an example of a totally un-sanitised output, which could be used to inject JavaScript into the page. A regular search will never cause problems with this type of code, but hackers simply need to send a link to the administrator of the site which uses carefully crafted javascript in the URL, and that JavaScript will be executed in the administrators browser without their permission.
https://gist.github.com/3848461
The correct way to display the search query back to the user is to sanitise it first. WordPress provides a range of standard functions for sanitizing different types of data inputs. You can read more about the various options on the Data Validation page at WordPress.org. The appropriate sanitization for an input field is esc_attr() which is intended for escaping attributes.
https://gist.github.com/3848471
Conveniently, WordPress goes one step further and includes a function specifically for search queries called get_search_query() which can be used as follows.
https://gist.github.com/3848476
Post requests
$_POST and $_REQUEST variables are used to access the values of submitted form fields. Form submission data must always be sanitized to ensure that malicious code is removed. It is important to ensure that the data is cleaned before using it for anything. Data must not be added to the database then sanitised afterwards as by that stage it may be too late to stop an attack. It is unfortunately common to see code resembling the following in WordPress plugins and themes.
https://gist.github.com/3848477
In this scenario, the raw post request is dumped directly into the database. The plugin or theme will then likely output that code to the end-user either in the admin panel or the front-end of the site. This would be a security catastrophe and must be avoided at all costs. Assuming that the data being submitted must be an integer, then the following code will ensure that the data is a valid integer before adding it to the database.
https://gist.github.com/3848479
If this submitted form data is perhaps a comment with some HTML, then it should be sanitised with a function which removes any potentially evil scripts; the wp_kses() function is ideal for this purpose.
https://gist.github.com/3848482
Server variables
Even developers who understand the concept of sanitising user submitted data often fail to appreciate the significance of displaying some server variables to site visitors. There are a range of server set variables which can be accessed from within PHP. Unfortunately, some of these can be manipulated by people wishing to display malicious code on your website. Through careful crafting of URL’s, the $_SERVER[‘PHP_SELF’] variable can be manipulated to display JavaScript on your site, and as we discussed earlier, you need to ensure that non-trusted users never have the ability to load custom JavaScript on your site. $_SERVER[‘PHP_SELF’] is used to determine the current page URL, but if the current page URL is not what you expected, then this can lead to alarming results, including the potential injection of JavaScript into pages.
Mark Jaquith wrote an excellent post on this type of security flaw. An examples given by Mark included use of $_SERVER[‘PHP_SELF’] in form fields as follows.
https://gist.github.com/3848484
It is rare to ever require $_SERVER values in WordPress plugins or themes, however if they are required then it is absolutely critical to escape/sanitise them. Since they are usually used within URL’s, the standard way to escape them is via the esc_url() function.
https://gist.github.com/3848488
Most form submissions can be submitted back to the current URL, voiding the need for using a $_SERVER variable at all.
https://gist.github.com/3848492
More security tips coming soon
These are only some of the most common security flaws found in WordPress plugins and themes. Also common are failures in user permission and user intention checks, which will be covered in a future article.
Nuno Morgadinho says:
Nice! Would also like to see WordPress Nonces covered (http://codex.wordpress.org/WordPress_Nonces). Cheers
October 11, 2012 at 2:21 pm # //
Ryan Hellyer says:
That’s what I was referring to by “User intention checks” at the end of the article 🙂
October 11, 2012 at 2:32 pm # //
shawn says:
would be cool to have a plugin that checks plugin for those issues, something that at least prints to screen what it finds and then tells me if it’s good or bad.
heck even a good grep command string or something that will search for all the generic problems would be nice to have. Plugins today can be enormous and trying to read through that much code, much less understand everything that is going on can be a daunting task even for the better coders.
October 11, 2012 at 2:52 pm # //
Ryan Hellyer says:
I was talking to Jon Cave about something like that at WordCamp Edinburgh. It should be possible to write something that can do a basic scan and look for potentially dodgy things and show you the code so you can double check it yourself.
October 11, 2012 at 3:22 pm # //
shawn says:
Now that would indeed make life much easier when it comes to dealing with plugins and themes. I’m definitely no expert as I already found myself doing some of the same things this article specifically says to avoid. Learned something new today, so its a good day
October 11, 2012 at 3:27 pm # //
Ryan Hellyer says:
The problem with any tool like that, is it wouldn’t find security flaws, just potential security flaws.
I have a vague pie in the sky of building a rather extensive testing tool, but I’m not sure if I’ll ever find the time to build or not.
October 11, 2012 at 3:30 pm # //
shawn says:
@Ryan
I totally understand. The hard part when you are new at this is just plain knowing what to look for. Having a tool that even found potential flaws would be very cool.
If you ever do find the time, I hope you can add a comment to this post as I will receive an email alert then.
Have a great day.
October 12, 2012 at 8:46 am # //
Ryan Hellyer says:
I will try to remember to do that. I’d say I’m about 20% likely to build it though. It’s an exciting concept, but it would also take a lot of work.
October 12, 2012 at 9:02 am # //
Paul says:
Maybe a better way to get the current page URL: home_url( $wp->request )
November 21, 2012 at 12:16 pm # //