writing secure wordpress code

58
WRITING SECURE WORDPRESS CODE BY BRAD WILLIAMS Brad Williams @williamsba

Upload: brad-williams

Post on 17-May-2015

22.696 views

Category:

Technology


3 download

DESCRIPTION

My WordCamp Europe 2013 presentation on writing secure WordPress code.

TRANSCRIPT

Page 1: Writing Secure WordPress Code

WRITING SECURE WORDPRESS CODE BY  BRAD  WILLIAMS  

Brad Williams @williamsba

Page 2: Writing Secure WordPress Code

WHO IS BRAD?

Brad Williams @williamsba

Brad  Williams    

Co-­‐Founder  WebDevStudios.com      Co-­‐Author  Professional  WordPress    

 &  Professional  WordPress        Plugin  Development  

   Co-­‐Organizer  WordCamp  Philly      

Co-­‐Host  DradCast  

Page 3: Writing Secure WordPress Code

TODAY’S TOPICS

Brad Williams @williamsba

 

• Cover  the  big  three  exploits  •  SQL  InjecLon  -­‐  SQLi  •  Cross-­‐Site  ScripLng  -­‐  XSS  •  Cross-­‐Site  Request  Forgery  –  CSRF  

• Hack  Examples  • Data  ValidaLon  and  SaniLzaLon  • Resources  

Page 4: Writing Secure WordPress Code

TRUST NO ONE

Brad Williams @williamsba

Golden  Rule  of  Code  

Trust  No  One  

Page 5: Writing Secure WordPress Code

TRUST NO ONE

Brad Williams @williamsba

Consider  all  data  invalid  unless  it  can  be  proven  valid  

Page 6: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

SQL  InjecLon  (SQLi)  

Page 7: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

SQL  injec*on  is  a  code  injecLon  technique,  used  to  aYack  data  driven  applicaLons,  in  

which  malicious  SQL  statements  are  inserted  into  an  entry  field  for  execuLon  

Page 8: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

SQL  InjecLon  Example    

global $wpdb; $ID = $_GET['ID']; $sql = "SELECT post_title FROM $wpdb->posts WHERE ID = '$ID';";

SELECT  post_Ltle  FROM  wp_posts  WHERE  ID  =  '5';  

Page 9: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

SQL  InjecLon  Example    

SELECT  post_Ltle  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';";

Page 10: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

hYp://www.sitepoint.com/forums/showthread.php?83772-­‐web-­‐site-­‐hacked  

My  IntroducLon  to  SQLi  

Page 11: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

hYp://www.sitepoint.com/forums/showthread.php?83772-­‐web-­‐site-­‐hacked  

My  IntroducLon  to  SQLi  

Page 12: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

$wpdb->insert()

Page 13: Writing Secure WordPress Code

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:  

Page 14: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

$wpdb->update()

Page 15: Writing Secure WordPress Code

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:  

Page 16: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

$wpdb->delete()

Page 17: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

$wpdb->delete( $wpdb->posts, array( 'ID' => 5 ), array( '%d' ) );

$wpdb->delete() $wpdb->delete( $table, $where, $where_format )

Example:  

Page 18: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

$wpdb->prepare()

Page 19: Writing Secure WordPress Code

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()

Page 20: Writing Secure WordPress Code

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()

Page 21: Writing Secure WordPress Code

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  

Page 22: Writing Secure WordPress Code

SQL INJECTION - SQLI

Brad Williams @williamsba

hYp://xkcd.com/327/  

Don’t  be  LiYle  Bobby  Tables  

Page 23: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

Cross-­‐Site  ScripLng    (XSS)  

Page 24: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

 What  is  Cross-­‐Site  ScripLng?  

 AYacker  injects  client-­‐side  scripts  into  your  web  pages  

Page 25: Writing Secure WordPress Code

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  

Page 26: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

1.  esc_  is  the  prefix  for  all  escaping  funcLons  2.  aYr  is  the  context  being  escaped  3.  _e  is  the  opLonal  translaLon  suffix  

Props  to  Mark  Jaquith!  

Escaping  

Page 27: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

<h1><?php echo $title; ?></h1>

BAD  

Page 28: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

<?php $title = "<script>alert('Hello Europe!');</script>"; ?> <h1><?php echo $title; ?></h1>

BAD  

Page 29: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

<?php $title = "<script>alert('Hello Europe!');</script>"; ?> <h1><?php echo esc_html( $title ); ?></h1>

View  Source:  <h1>&lt;script&gt;alert(&#039;Hello Europe!&#039;);&lt;/script&gt;</h1>

GOOD  

Page 30: Writing Secure WordPress Code

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  

hYp://codex.wordpress.org/FuncLon_Reference/esc_aYr  

Page 31: Writing Secure WordPress Code

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  

hYp://codex.wordpress.org/FuncLon_Reference/esc_textarea  

Page 32: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

<a href="<?php echo esc_url( $url); ?>">Link</a>

esc_url()  Used  for  validaLng  and  saniLzing  URLs  

hYp://codex.wordpress.org/FuncLon_Reference/esc_url  

Page 33: Writing Secure WordPress Code

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  enLLes  for  display  

hYp://codex.wordpress.org/FuncLon_Reference/esc_url_raw  

Page 34: Writing Secure WordPress Code

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  

hYp://codex.wordpress.org/FuncLon_Reference/esc_js  

Page 35: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

Integers  

Page 36: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

$ID = absint( $_GET['ID'] );

absint() Coverts  a  value  to  a  non-­‐negaLve  integer  

hYp://codex.wordpress.org/FuncLon_Reference/absint  

<input type="text" name="number_posts" value="<?php echo absint( $number ); ?>" />

Page 37: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

$ID = intval( $_GET['ID'] );

intval() Returns  the  integer  value.    Works  with  negaLve  values  

hYp://php.net/manual/en/funcLon.intval.php  

<input type="text" name="number_posts" value="<?php echo intval( $number ); ?>" />

Page 38: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

SaniLzing  To  saniLze  is  to  take  the  data  and  clean  

to  make  safe  

Page 39: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

<?php update_post_meta(

420,

'_post_meta_key',

$_POST['new_meta_value'] ); ?>

BAD  

Page 40: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

sanitize_text_field() SaniLze  a  string  

hYp://codex.wordpress.org/FuncLon_Reference/saniLze_text_field  

<?php update_post_meta(

34,

'_post_meta_key',

sanitize_text_field( $_POST['new_meta_value'] ) ); ?>

Page 41: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

sanitize_email() Strip  out  all  characters  not  allowed  in  an  email  address  

hYp://codex.wordpress.org/FuncLon_Reference/saniLze_email  

<?php update_post_meta(

34,

'_email_address',

sanitize_email( $_POST['email'] ) ); ?>

Page 42: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

sanitize_user() SaniLze  username  stripping  out  unsafe  characters  

hYp://codex.wordpress.org/FuncLon_Reference/saniLze_user  

<?php update_post_meta(

34,

'_custom_username',

sanitize_user( $_POST['username'] ) ); ?>

Page 43: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

wp_kses() Filters  content  and  keeps  only  allowable  HTML  elements.  

hYp://codex.wordpress.org/FuncLon_Reference/wp_kses  

<a  href="#">link</a>.  This  is  bold  and  <strong>strong</strong>  

Page 44: Writing Secure WordPress Code

CROSS-SITE SCRIPTING - XSS

Brad Williams @williamsba

wp_kses_post() Filters  post  content  and  keeps  only  allowable  HTML  elements.  

hYp://codex.wordpress.org/FuncLon_Reference/wp_kses_post  

HTML  tags  allowed  to  be  put  into  Posts  by  non-­‐admin  users  

Page 45: Writing Secure WordPress Code

CROSS-SITE REQUEST FORGERY - CSRF

Brad Williams @williamsba

Cross-­‐site  Request  Forgery  (CSRF)  

Page 46: Writing Secure WordPress Code

CROSS-SITE REQUEST FORGERY - CSRF

Brad Williams @williamsba

Exploit  of  a  website  whereby  unauthorized  commands  are  transmiYed  from  a  user  that  the  website  trusts.  

Cross-­‐site  Request  Forgery  (CSRF)  

Page 47: Writing Secure WordPress Code

CROSS-SITE REQUEST FORGERY - CSRF

Brad Williams @williamsba

Nonces  AcLon,  object,  &  user  specific  Lme-­‐

limited  secret  keys  

Page 48: Writing Secure WordPress Code

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  

Page 49: Writing Secure WordPress Code

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:  

hYp://codex.wordpress.org/FuncLon_Reference/wp_nonce_field  

wp_nonce_field( $action, $name, $referer, $echo );

Page 50: Writing Secure WordPress Code

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 );

hYp://codex.wordpress.org/FuncLon_Reference/check_admin_referer  

Page 51: Writing Secure WordPress Code

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  

Page 52: Writing Secure WordPress Code

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:  

hYp://codex.wordpress.org/FuncLon_Reference/wp_nonce_url  

wp_nonce_url( $actionurl, $action, $name );

Page 53: Writing Secure WordPress Code

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:  

hYp://codex.wordpress.org/FuncLon_Reference/check_admin_referer  

Page 54: Writing Secure WordPress Code

CROSS-SITE REQUEST FORGERY - CSRF

Brad Williams @williamsba

Nonces  Specific  to  

• WordPress  User  • AcLon  AYempted  • Object  of  aYempted  acLon  • Time  Window  

Page 55: Writing Secure WordPress Code

RESOURCES

Brad Williams @williamsba

•  Security  ArLcles  •  hYp://codex.wordpress.org/Data_ValidaLon  •  hYp://codex.wordpress.org/ValidaLng_SaniLzing_and_Escaping_User_Data  •  hYp://wp.tutsplus.com/tutorials/7-­‐simple-­‐rules-­‐wordpress-­‐plugin-­‐development-­‐best-­‐

pracLces/  •  hYp://wpengine.com/2013/05/brad-­‐williams-­‐on-­‐secure-­‐wordpress-­‐development/  

•  Security  PresentaLons  •  hYp://wordpress.tv/2013/08/09/mike-­‐adams-­‐three-­‐security-­‐issues-­‐you-­‐thought-­‐youd-­‐fixed/  •  hYp://wordpress.tv/2013/09/26/brennen-­‐byrne-­‐employing-­‐best-­‐security-­‐pracLces-­‐for-­‐

wordpress-­‐sites-­‐3/  •  hYp://wordpress.tv/2011/01/29/mark-­‐jaquith-­‐theme-­‐plugin-­‐security/  

 

Page 56: Writing Secure WordPress Code

DRADCAST PLUG

Brad Williams @williamsba

Listen  to  the  DradCast  WordPress  Podcast    

                                       LIVE  every  Wednesday  @  8pm  EDT    

DradCast.com  

Page 57: Writing Secure WordPress Code

RESOURCES

Brad Williams @williamsba

#wceu after party

Drink  Time!  

Page 58: Writing Secure WordPress Code

CONTACT BRAD

Brad Williams @williamsba

Brad  Williams  [email protected]    Blog:    strangework.com  TwiYer:  @williamsba      

Professional  WordPress  Second  EdiLon  is  OUT!  

hYp://bit.ly/prowp2