WordPress.org

Ready to get started?Download WordPress

Codex

Attention Interested in functions, hooks, classes, or methods? Check out the new WordPress Code Reference!

User:Jalenack/Plugin Security

This article is a ROUGH DRAFT. The author is still working on this document, so please do not edit this without the author's permission. The content within this article may not yet be verified or valid. This information is subject to change.

WordPress Plugins can create significant problems for the security of the rest of the system. They don't get put under the close scrutiny that the core WordPress files get. Following a few guidelines will help make your plugins more secure. Moral of the story: Never trust the user!

Admin Panel Interaction

Plugins that use Admin Panels must pay special attention to make sure only authorized users can change options. That means making sure any $_GET or $_POST requests are from authorized users only. Someone up to no good could figure out the $_GET and $_POST requests by looking at the code in a plugin file, and maliciously change option without being in the admin panel. We need to protect ourselves from this kind of attack. A simple way to do this would be to check the user's cookie and make sure they're logged in and of high enough user level. Normally we would do something like this:

if (isset($_GET['jal_edit'])) {
  
//do edit stuff

}

The problem is that the get_currentuserinfo() function isn't available from there. It is available on the initialization of WordPress, so we can hook into that using Plugin Hooks. From there, we can call a function that will check the logged in user and then change options in the admin panel.

if (isset($_GET['jal_edit'])) {
    add_action('init', 'jal_shout_edit');
}

function jal_shout_edit () {

// do edit stuff

}

Using get_currentuserinfo()

The get_currentuserinfo() function will read a users cookie and match it to the database, making sure they are who they say they are. It returns information about the user as well. Also, when writing functions, you must declare the globals you are going to use. Note: You must declare the user variables you're going to use. In this case, we are going to make sure that the user is at least user level 8, so we declare the $user_level global and then test it against the current user. If they are less than level 8, we'll shut down everything and tell the user they aren't allowed.

if (isset($_GET['jal_edit_options'])) {
    add_action('init', 'jal_shout_edit');
}


function jal_edit_options () {
    global $user_level;
    
    get_currentuserinfo();
    if ($user_level <  8) die('Nice try, you cheeky monkey!');

    // do edit stuff
}

Interaction with the Database

Now that we've weeded out the unauthorized users, we can edit some options. In the code below, we'll change some text in the database, by using the information the user has submitted. Any time we change the data in the database, we need to use $wpdb->escape() to escape the data so that it's ready for the database. Using $wpdb requires that we declare the $wpdb and $table_prefix globals. We'll also use the update_option() function to update some other options. Note that the update_option() function automatically escapes data that is sent through it.

if (isset($_GET['jal_edit_options'])) {
    add_action('init', 'jal_shout_edit');
}

function jal_edit_options () {
    global $user_level, $wpdb, $table_prefix;
    
    get_currentuserinfo();
    if ($user_level <  8) die('Nice try, you cheeky monkey!');

    $text = $wpdb->escape($_GET['jal_text']);
    $id = $wpdb->escape($_GET['jal_comment_id'])

    $wpdb->query("UPDATE ".$table_prefix."liveshoutbox SET text = '".$text."' WHERE id = ".$id);

    update_option('shoutbox_name_color', $_GET['shoutbox_name_color']);
}

Notes

You should always escape user data. Never trust that a user will input what you think they will. WordPress uses $wpdb->escape() to prepare data for the database. When pulling data out of the database, you may need to use stripslashes() to get take away slashes added when the data is escaped.

It might be more user-friendly if you define the user level required to edit options at the top of the plugin file. Then if a site admin wants to let his/her other users manage the plugin, all they will have to do is change one variable.

WordPress automatically quotes $_GET, $_POST, and some other globals in wp-settings.php. This may mean that input used directly from those variables should NOT be $wpdb->Escape()'d. See note at http://codex.wordpress.org/Function_Reference/wpdb_Class#escape_-_Escape_For_SQL_Queries