Post on 08-Sep-2014
description
WRITING SECURE WORDPRESS CODE BY BRAD WILLIAMS
Brad Williams @williamsba
h-p://www.slideshare.net/williamsba/wri>ng-‐secure-‐wordpress-‐code-‐wordcamp-‐nyc-‐2014
WHO IS BRAD?
Brad Williams @williamsba
Brad Williams
CO-HOST DRADCAST
Brad Williams @williamsba
TODAY’S TOPICS
Brad Williams @williamsba
• Cover the big three exploits • SQL Injec>on -‐ SQLi • Cross-‐Site Scrip>ng -‐ XSS • Cross-‐Site Request Forgery – CSRF
• Hack Examples • Data Valida>on and Sani>za>on • Resources
TRUST NO ONE
Brad Williams @williamsba
Golden Rule of Code
Trust No One
TRUST NO ONE
Brad Williams @williamsba
Consider all data invalid unless it can be proven valid
SQL INJECTION - SQLI
Brad Williams @williamsba
SQL Injec>on (SQLi)
SQL INJECTION - SQLI
Brad Williams @williamsba
SQL injec*on is a code injec>on technique in which malicious SQL statements are inserted into an entry field for execu>on
SQL INJECTION - SQLI
Brad Williams @williamsba
SQL Injec>on Example global $wpdb;
$ID = $_GET['ID']; $sql = "SELECT post_title FROM $wpdb->posts WHERE ID = '$ID';";
SELECT post_>tle FROM wp_posts WHERE ID = '5';
SQL INJECTION - SQLI
Brad Williams @williamsba
SQL Injec>on Example
SELECT post_>tle FROM wp_posts WHERE ID = ''; SELECT * FROM wp_users WHERE 1 = '1';
global $wpdb; $ID = "'; SELECT * FROM wp_users WHERE 1 = '1"; $sql = "SELECT post_title FROM $wpdb->posts WHERE ID = '$ID';";
SQL INJECTION - SQLI
Brad Williams @williamsba
h-p://www.sitepoint.com/forums/showthread.php?83772-‐web-‐site-‐hacked
My Introduc>on to SQLi
SQL INJECTION - SQLI
Brad Williams @williamsba
h-p://www.sitepoint.com/forums/showthread.php?83772-‐web-‐site-‐hacked
My Introduc>on to SQLi
SQL INJECTION - SQLI
Brad Williams @williamsba
WordPress Database Class
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb->insert()
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb->insert( $wpdb->postmeta, array( 'post_id' => '5', 'meta_key' => '_custom_meta_key', 'meta_value' => 'true' ), array( '%d', '%s', '%s' ) );
$wpdb->insert() $wpdb->insert( $table, $data, $format )
Example:
%s handles strings %d handles integers %f handles floats
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb->update()
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb->update( $wpdb->postmeta', array( 'meta_value' => 'false' ), array( 'post_id' => 5, 'meta_key' => '_custom_meta_key' ), array( '%s' ), array( '%d', '%s' ) );
$wpdb->update() $wpdb->update( $table, $data, $where, $format, $where_format )
Example:
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb->delete()
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb->delete( $wpdb->posts, array( 'ID' => 5 ), array( '%d' ) );
$wpdb->delete() $wpdb->delete( $table, $where, $where_format )
Example:
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb->prepare()
SQL INJECTION - SQLI
Brad Williams @williamsba
• Handles strings (%s) and integers (%d)
• Does the escaping for you • No need to quote %s
$wpdb->prepare( " SELECT post_title FROM $wpdb->posts WHERE ID = %d ", $ID );
$wpdb->prepare()
SQL INJECTION - SQLI
Brad Williams @williamsba
• Handles strings (%s) and integers (%d)
• Does the escaping for you • No need to quote %s
$wpdb->prepare( " DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s ", 420, 'Europe' );
$wpdb->prepare()
SQL INJECTION - SQLI
Brad Williams @williamsba
$wpdb-‐>prepare() only prepares the query, it does not execute it.
$wpdb->query( $wpdb->prepare( " DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s ", 420, 'Europe' ) );
$wpdb->prepare()
echo $wpdb->prepare( " DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s ", 420, 'Europe' );
To view the fully prepared query simply echo it
SQL INJECTION - SQLI
Brad Williams @williamsba
h-p://xkcd.com/327/
Don’t be Li-le Bobby Tables
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
Cross-‐Site Scrip>ng (XSS)
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
What is Cross-‐Site Scrip>ng?
A-acker injects client-‐side scripts into your web pages
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
Escaping To escape is to take the data you may already have and help secure it prior to
rendering it for the end user
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
1. esc_ is the prefix for all escaping func>ons 2. a-r is the context being escaped 3. _e is the op>onal transla>on suffix
Props to Mark Jaquith!
Escaping
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<h1><?php echo $title; ?></h1>
BAD
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<?php $title = "<script>alert('YO!');</script>"; ?> <h1><?php echo $title; ?></h1>
BAD
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<?php $title = "<script>alert('Hello Europe!');</script>"; ?> <h1><?php echo esc_html( $title ); ?></h1>
View Source: <h1><script>alert('Hello Europe!');</script></h1>
GOOD
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<input type="text" name="name" value="<?php echo esc_attr( $text ); ?>" />
esc_attr() Used whenever you need to display data inside an HTML element
h-p://codex.wordpress.org/Func>on_Reference/esc_a-r
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<textarea name="bio"> <?php echo esc_textarea( $bio); ?> </textarea>
esc_textarea() Used to encode text for use in a <textarea> form element
h-p://codex.wordpress.org/Func>on_Reference/esc_textarea
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<a href="<?php echo esc_url( $url); ?>">Link</a>
esc_url() Used for valida>ng and sani>zing URLs
h-p://codex.wordpress.org/Func>on_Reference/esc_url
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<?php $url = 'http://wordpress.org'; $response = wp_remote_get( esc_url_raw( $url ) ); ?>
esc_url_raw() Used for escaping a URL for database queries, redirects, and HTTP requests
Similar to esc_url(), but does not replace en>>es for display
h-p://codex.wordpress.org/Func>on_Reference/esc_url_raw
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<script> var bwar='<?php echo esc_js( $text ); ?>'; </script>
esc_js() Used to escape text strings in JavaScript
h-p://codex.wordpress.org/Func>on_Reference/esc_js
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
Integers
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
$ID = absint( $_GET['ID'] );
absint() Coverts a value to a non-‐nega>ve integer
h-p://codex.wordpress.org/Func>on_Reference/absint
<input type="text" name="number_posts" value="<?php echo absint( $number ); ?>" />
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
$ID = intval( $_GET['ID'] );
intval() Returns the integer value. Works with nega>ve values
h-p://php.net/manual/en/func>on.intval.php
<input type="text" name="number_posts" value="<?php echo intval( $number ); ?>" />
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
Sani>zing To sani>ze is to take the data and clean
to make safe
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
<?php update_post_meta(
420,
'_post_meta_key',
$_POST['new_meta_value'] ); ?>
BAD
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
sanitize_text_field() Sani>ze a string
h-p://codex.wordpress.org/Func>on_Reference/sani>ze_text_field
<?php update_post_meta(
34,
'_post_meta_key',
sanitize_text_field( $_POST['new_meta_value'] ) ); ?>
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
sanitize_email() Strip out all characters not allowed in an email address
h-p://codex.wordpress.org/Func>on_Reference/sani>ze_email
<?php update_post_meta(
34,
'_email_address',
sanitize_email( $_POST['email'] ) ); ?>
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
sanitize_user() Sani>ze username stripping out unsafe characters
h-p://codex.wordpress.org/Func>on_Reference/sani>ze_user
<?php update_post_meta(
34,
'_custom_username',
sanitize_user( $_POST['username'] ) ); ?>
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
wp_kses() Filters content and keeps only allowable HTML elements.
h-p://codex.wordpress.org/Func>on_Reference/wp_kses
<a href="#">link</a>. This is bold and <strong>strong</strong>
CROSS-SITE SCRIPTING - XSS
Brad Williams @williamsba
wp_kses_post() Filters post content and keeps only allowable HTML elements.
h-p://codex.wordpress.org/Func>on_Reference/wp_kses_post
HTML tags allowed to be put into Posts by non-‐admin users
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
Cross-‐site Request Forgery (CSRF)
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
Exploit of a website whereby unauthorized commands are transmi-ed from a user that the website trusts.
Cross-‐site Request Forgery (CSRF)
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
Nonces Ac>on, object, & user specific >me-‐
limited secret keys
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
<?php if ( isset( $_POST['email'] ) ) { //process form data } ?> <form method="post"> <input type="text" name="email /><br /> <input type="submit" name="submit" value="Submit" /> </form>
Example
There is no way to know where $_POST[‘email’] is being posted from
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
<form method="post"> <?php wp_nonce_field( 'bw_process_email_action', 'bw_newsletter' ); ?> <input type="text" name="email" /><br /> <input type="submit" name="submit" value="Submit" /> </form>
wp_nonce_field()
<form method="post"> <input type="hidden" id="bw_newsletter" name="bw_newsletter" value="287de957e8" /> <input type="hidden" name="_wp_http_referer" value="/x/sample-page/" /> <input type="text" name="email" /><br /> <input type="submit" name="submit" value="Submit" /> </form>
View Source:
Form Code:
h-p://codex.wordpress.org/Func>on_Reference/wp_nonce_field
wp_nonce_field( $action, $name, $referer, $echo );
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
if ( isset( $_POST['email'] ) ) { check_admin_referer( 'bw_process_email_action', 'bw_newsletter' ); //process form data }
check_admin_referer()
Processing Code:
check_admin_referer( $action, $query_arg );
h-p://codex.wordpress.org/Func>on_Reference/check_admin_referer
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
<?php if ( isset( $_POST['email'] ) ) { check_admin_referer( 'bw_process_email_action', 'bw_newsletter' ); //process form data } ?> <form method="post"> <?php wp_nonce_field( 'bw_process_email_action', 'bw_newsletter' ); ?> <input type="text" name="email" /><br /> <input type="submit" name="submit" value="Submit" /> </form>
Fixed Example
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
$url = 'http://example.com/wp-admin/?ID=5'; $url = wp_nonce_url( $url, 'bw_process_email_action', 'bw_newsletter' );
wp_nonce_url()
http://example.com/wp-admin/?ID=5&bw_newsletter=287de957e8 New URL:
URL Code:
h-p://codex.wordpress.org/Func>on_Reference/wp_nonce_url
wp_nonce_url( $actionurl, $action, $name );
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
if ( isset( $_GET[ID'] ) ) { check_admin_referer( 'bw_process_email_action', 'bw_newsletter' ); //process data }
wp_nonce_url()
Processing Code:
h-p://codex.wordpress.org/Func>on_Reference/check_admin_referer
CROSS-SITE REQUEST FORGERY - CSRF
Brad Williams @williamsba
Nonces Specific to
• WordPress User • Ac>on A-empted • Object of a-empted ac>on • Time Window
RESOURCES
Brad Williams @williamsba
• Security Ar>cles • h-p://codex.wordpress.org/Data_Valida>on • h-p://codex.wordpress.org/Valida>ng_Sani>zing_and_Escaping_User_Data • h-p://wp.tutsplus.com/tutorials/7-‐simple-‐rules-‐wordpress-‐plugin-‐development-‐best-‐
prac>ces/ • h-p://wpengine.com/2013/05/brad-‐williams-‐on-‐secure-‐wordpress-‐development/ • h-p://codex.wordpress.org/WordPress_Nonces
• Security Presenta>ons • h-p://wordpress.tv/2013/08/09/mike-‐adams-‐three-‐security-‐issues-‐you-‐thought-‐youd-‐fixed/ • h-p://wordpress.tv/2013/09/26/brennen-‐byrne-‐employing-‐best-‐security-‐prac>ces-‐for-‐
wordpress-‐sites-‐3/ • h-p://wordpress.tv/2011/01/29/mark-‐jaquith-‐theme-‐plugin-‐security/
DRADCAST PLUG
Brad Williams @williamsba
Listen to the DradCast WordPress Podcast
LIVE every Wednesday @ 8pm EDT
DradCast.com
CONTACT BRAD
Brad Williams @williamsba
Brad Williams brad@webdevstudios.com Blog: strangework.com Twi-er: @williamsba
h-p://bit.ly/prowp2