Writing Secure
Plugins and Themes

The WordPress Way

By Ben Lobaugh / @benlobaugh

Not about website security!

This presentation is about writing secure code, not how to secure an entire website

Thinking about security is important!

  • 22%+ of the internet runs WordPress
  • One plugin/theme vulnerability can bring down MILLIONS of sites!

Breathe, even the "pros" fail

  • Pippin - https://pippinsplugins.com/i-wrote-some-really-dangerous-code/
  • Automattic - Recent major security patch to Jetpack
  • Yoast SEO - Multiple vulnerabilities in the past

Use clear consistent coding standards

  • Makes code easier to read and understand
  • Can prevent common mistakes

Enable WP_DEBUG

Prevent direct file access


if ( ! defined( 'ABSPATH' ) ) exit;

Timthumb anyone?

TRUST NO ONE

All data should be considered invalid until proven valid

SQL Injections

Little Bobby Drop Tables

Displaying unsanitized $_POST input

Search results display page example

Unsanitized $_GET variables

Sometimes forgotten when not created by a form input

Escaping vs Sanitizing vs Validation

Escaping

Make sure the data is safe for display

Sanitizing

Make sure the data is safe for storing in the database

Validation

Ensuring data provided is in a valid format before attempting to process it

Functions to Escape

wp_kses()

Strips out all but allowed HTML tags

esc_html()

Encodes characters common to HTML such as < and >

esc_attr()

Makes a string safe to use in HTML tag attributes

esc_url()

Ensures urls contain only valid characters

urlencode()

Makes a full url safe


Part of the PHP language

Functions to Sanitize

Many of the Escape functions can be used as well

wp_kses()

Strips out all but allowed HTML tags

  • sanitize_title()
  • sanitize_user()
  • balanceTags()
  • sanitize_email()
  • sanitize_file_name()
  • sanitize_user()
  • sanitize_meta()
  • And more... http://codex.wordpress.org/Data_Validation#Other

Functions to validate

is_email()

Ensure valid email address

filter_var()

Validates based on passed in filter.
Supported types:

  • Boolean
  • Email
  • Float
  • Int
  • IP
  • Regexp - you provide
  • URL

Checking numbers

  • is_int()
  • is_numeric()
  • is_float()

More is_s

  • is_bool()
  • is_string()
  • is_object()
  • is_array()

Verify user permissions

User capabilities

  • read
  • manage_options
  • edit_posts
  • jetpack_connect
  • jetpack_manage_modules

current_user_can()

Ensure user requested action

Nonce

A nonce is a number used once.

Nonces are used to sign actions for the user.

wp_nonce_url()

Add nonce to query variable

wp_nonce_field()

Creates a hidden form element

wp_create_nonce()

Returns a single nonce

check_admin_referer()

Verify nonce in wp-admin

check_ajax_referer()

Verify nonce in ajax request

wp_verify_nonce()

Verify any type of nonce

$wpdb

$wpdb is your friend!

Database table prefix

$wpdb->prefix

Table names

Of form $wpdb->post

  • $post
  • $postmeta
  • $comments
  • $commentmeta
  • $terms
  • $term_taxonomy
  • $term_relationships
  • $users
  • $usermeta
  • $options

Escaping queries

$wpdb->prepare()

Running the query

$wpdb->query()

Load only what is needed

Check for wp-admin

is_admin()

Check which page this is on

is_page()

Check tags and categories

  • is_category()
  • is_tag()

Clean up after yourself

Plugin deactivation

register_deactivation_hook()

Disable wp-cron jobs

wp_unschedule_event()

Plugin uninstall

register_uninstall_hook()

Questions?

BY Ben Lobaugh / ben.lobaugh.net / @benlobaugh