Writing Secure WordPress Plugins
Title: Writing Secure WordPress Plugins (part 1)
Author: David Kierznowski
Site: Operation n
Date: 17 May 2007
Table of Contents
Introduction
WordPress has become one of the most popular blogging packages on the Internet; this is largely due to its ease of use and its object oriented design which allows the user to easily extend its capabilities in the form of WordPress Plugins.
Unfortunately, "ease of use", and "security" are to often like lemon and milk. This article is a desparate attempt to try and educate WordPress Plugin developers to some of the common security problems that can occur. The reality is, that this article is a bit to late, and unfortunately countless plugins are vulnerable to the attacks discussed here.
What does this mean? Well, it means that an attacker could potentially gain access to your WordPress Admin Panel, or take control of areas of your blogs such as your Google Adsense ads - maybe the attacker wants a little extra pocket money.
On the positive side, WordPress itself, does support a number of built in security functions to help combat these issues.
Rather then tackling all the problems in one go, this paper introduces 2 common pitfalls developers are making when writing WordPress plugins. After going through this article I hope developers of plugins (especially popular ones) will begin immediately working to resolve these issues. When this occurs, we’ll look at part 2 of this article.
I am hesitent to release this information as I know just how many plugins these vulnerabilities affect. For this reason, I will try not discuss to much on the exploitation side (although both are fairly trivial to exploit), but rather give guidelines to follow.
attribute_escape
Right lets get into it… the functions we will be discussing are "attribute_escape" and "wp_nonce_field".
Firstly, the attribute_escape function is defined as follows:
applied to post text and other content by the attribute_escape function, which is called in many places in WordPress to change certain characters into HTML attributes before sending to the browser.
You should use this function everytime you intend to echo back data to the user. This generally means all strings from $_GET and $_POST. Lets have an example to illustrate this (this vulnerable code is actually taken from a plugin):
if( isset($_POST['name']) && $_POST['name'] != ''
&& isset($_POST['code']) && $_POST['code'] != '' ){
$desc = $_POST['comment'];
....
Now can you spot any problems in the above snippet of code? The problem here, is that the plugin is accepting any value that the user chooses as part of the POST variable named desc. This is not good, as any input including HTML entities will be echoed back to the users browser - Note, this also applies to $_GET as well (it even extends to other global variables supported by PHP, but that is beyond the scope of this paper). So lets secure this using the WordPress attribute_escape function:
if( isset($_POST['name']) && $_POST['name'] != ''
&& isset($_POST['code']) && $_POST['code'] != '' ){
$desc = attribute_escape($_POST['comment']);
....
Notice how simple it is to implement this function.
Lets have a $_GET example (also taken from a plugin):
if ( isset($_GET['mode']) ) {
$mode = $_GET['mode'];
...
Again, we see that we fail to escape our request from the user with add_attribute. So lets add it:
if ( isset($_GET['mode']) ) {
$mode = attribute_escape($_GET['mode']);
...
Applying attribute_escape will greatly increase the security of your plugin. Remember the basic rule, if your plugin echoes back data to the user, ensure that attribute_escape is being used before this occurs.
wp_nonce
Our next security feature to our script is to add a random nonce value when using forms. The WordPres definition is as follows:
explain_nonce_(verb)-(noun)
allows a filter function to define text to be used to explain a nonce that is otherwise not explained by the WordPress core code. You will need to define specific verb/noun filters to use this. For instance, if your plugin defines a nonce for updating a tag, you would define a filter for “explain_nonce_update-tag”. Filter function arguments: text to display (defaults to a generic “Are you sure you want to do this?” message) and extra information from the end of the action URL. In the example here, your function might simply return the string “Are you sure you want to update this tag?”.
There is typically three parts to this:
1st, we check to see if this functionality exists and set it at the top of our plugin:
if ( !function_exists('wp_nonce_field') ) {
function myplugin_nonce_field($action = -1) { return; }
$myplugin_nonce = -1;
} else {
function myplugin_nonce_field($action = -1) { return wp_nonce_field($action); }
$myplugin_nonce = 'myplugin-update-key';
}
2nd, we declare our newly generated random nonce into our POST form:
<form action= ...>
<?php adsense_nonce_field('$myplugin_nonce', $myplugin_nonce); ?>
...
Finally, we check the nonce is correct in our $_POST request:
if ( isset($_POST['submit']) ) {
if ( function_exists('current_user_can') && !current_user_can('manage_options') )
die(__('Cheatin’ uh?'));
check_admin_referer( '$myplugin_nonce', $adsense_nonce );
Each POST request will now contain a random number that is required in order to make the POST request. It is slightly more difficult to implement then the previous one, but not at all complicated when thought through.
You may have noticed that this addresses POST, but what about GET requests?
$delete_url = wp_nonce_url($get_url . "mode=del", '$adsense_nonce' . $myplugin_nonce);
The above will provide our nonce into the URL, now we just need to have it confirmed in our $_GET function:
if($mode == 'del' ){
check_admin_referer('$myplugin_nonce', $myplugin_nonce);
And your done… now make sure to test it :)
Summary
It is vital for the security of future WordPress plugins that attribute_escape and wp_nonce functions be used to prevent critical vulnerabilities which currently affect many such plugins.
I encourage developers to modify their plugins to reflect these changes. Forgive me if their are blatent errors in the paper, I wrote it quite late while fixing a vulnerable plugin…well I’m off to bed.
References
If you enjoyed this post, please leave a comment or subscribe to the feed and get future articles delivered to your feed reader.
The isset() function only checks that the value has been set which means you can have an empty variable and it will pass your if statements.
A better function to use would be !empty() that also checks that the variable has something in it and is not 0 or null.
Hello!
Thanks for writing this article. It is helpful to see examples of this stuff written out clearly.
For those that don’t know what a nonce is (the description from the documentation is confusing as heck): http://en.wikipedia.org/wiki/Cryptographic_nonce
In security engineering, a nonce is a number or bit string used only once. It is often a random or pseudo-random number issued in an authentication protocol to ensure that old communications cannot be reused in replay attacks.
I understand why I want to use attribute_escape: To prevent malicious HTML to be displayed.
I understand when I want to use attribute_escape: Anytime I display data that may have come from an untrusted source; yes, the blogger herself/himself is untrusted.
When would I want to use a nonce?
What am I gaining by using a nonce?
Thanks again for writing the article!
Ciao!
dochwat,
The nonce is used to prevent CSRF attacks.
Have a look and let me know if you need further details.
[...] tanto del core de Wordpress como de algunos plugins, también se publicó material sobre como desarrollar plugins seguros y hasta dado consejos para mejorar la seguridad de un blog; sin embargo, parece que este esfuerzo [...]
[...] este artÃculo, nos explican como mejorar la seguridad de nuestros plugins usando una serie de funciones del [...]
Shouldn’t be htmlspecialchars also be fine, or why is there attribute_escape used? Does it something else than htmlspecialchars?
Nice article, btw.
Philipp,
Yes, htmlspecialchars is fine too; however, because this article involves WordPress, I was demonstrating its own built-in security features, either can be used.
[...] This article was originally written by David Kierznowski from Operation n, titled, "Writing Secure WordPress Plugins (part 1)". [...]
[...] Artikel von David Kierznowski ist zwar auf Englisch, aber wer Plugins programmiert sollte sich Writing Secure WordPress Plugins durchlesen.Nicht nur im Zusammenhang mit dem Wettbewerb den es hier demnächst gibt ist es ein [...]
When is the correct time to call current_user_can() and check_admin_referer()?
If I call them just within and if( is_admin() ) block, then I get an error that wp_current_user_can() doesn’t exist.
If I call them within the function for creating the plugin’s option form, then the headers are already sent, which causes check_admin_referer() to spew php warnings if the nonce is missing/incorrect.
Any ideas?
[...] Escribiendo Plugins Seguros de WordPress : Este es un tópico importante y con la venidera competencia de plugins, realmente me gustarÃa resaltar la importancia de incluir seguridad en los plugins de WordPress. Este artÃculo explica las funciones de seguridad incluÃdas en WordPress y su marco de trabajo y discute los items mas comunmente usados incluyendo attribute_escape y wp_nonce y explica como usarlos en tus plugins. Esta es una lectura esencial para desarrolladores de plugins si no están incluyendo seguridad en sus plugins. (No Ratings Yet) Loading … [...]
[...] more Posted by wordpressblogger Filed in security, tech news, wordpress plugins, wordpress security, [...]
[...] Writing Secure WordPress Plugins: This is an important topic and with the upcoming plugin competition, I would really like to highlight the importance of securing your Wordpress plugins. This article explains the security features built into Wordpress and its plugin framework and discusses the most commonly used items including attribute_escape and wp_nonce and how to use them in your plugins. This is an essential read for plugin developers if you are not building security into your plugins. make money online, technology, blogging, make money from home, work from home Written by on June 7th, 2007 with no comments. Read more articles on Blogging. [...]
[...] Le plugin ne se prête pas vraiment au jeu de la sécurisation des plugins mais sachez qu’il existe un excellent tutoriel en anglais sur la sécurisation des plugins WordPress. [...]
[...] Für die Zukunft: Ein netter Artikel über Sicherheit bei der Entwicklung von Plugins für Wordpress: Writing Secure WordPress Plugins [...]
WPtags 4 MetaKeywords…
[...] Added some features to the plugin?s administration-page to enhance security. Changes were inspired by this great article from David Kierznowski. [...]…
[...] Operation n » Writing Secure WordPress Plugins (tags: wordpress plugin writing security) [...]
[...] used with forms but it can be used with links. About the only source on this function is the Writing Secure Wordpress Plugins post by David Kierznowski. I think when I have to log back into WordPress, wp_nonce thinks I am [...]


[...] seguros para Wordpress “Es vital para la seguridad de los plugins en Wordpress usar las funciones attribute_escape y wp_nonce, como medida de prevención para las vulnerabilidades crÃticas que afectan en la actualidad a [...]