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
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.
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.
Conveniently, WordPress goes one step further and includes a function specifically for search queries called get_search_query() which can be used as follows.
$_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.
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.
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.
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.
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.
Most form submissions can be submitted back to the current URL, voiding the need for using a $_SERVER variable at all.
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.