Writing Secure WordPress Code

24,726 views
24,484 views

Published on

My WordCamp Europe 2013 presentation on writing secure WordPress code.

Published in: Technology
0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
24,726
On SlideShare
0
From Embeds
0
Number of Embeds
8,695
Actions
Shares
0
Downloads
65
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide

Writing Secure WordPress Code

  1. 1. WRITING SECURE WORDPRESS CODE BY  BRAD  WILLIAMS   Brad Williams @williamsba
  2. 2. 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  
  3. 3. 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  
  4. 4. TRUST NO ONE Brad Williams @williamsba Golden  Rule  of  Code   Trust  No  One  
  5. 5. TRUST NO ONE Brad Williams @williamsba Consider  all  data  invalid   unless  it  can  be  proven  valid  
  6. 6. SQL INJECTION - SQLI Brad Williams @williamsba SQL  InjecLon  (SQLi)  
  7. 7. 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  
  8. 8. 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';  
  9. 9. 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';";
  10. 10. SQL INJECTION - SQLI Brad Williams @williamsba hYp://www.sitepoint.com/forums/showthread.php?83772-­‐web-­‐site-­‐hacked   My  IntroducLon  to  SQLi  
  11. 11. SQL INJECTION - SQLI Brad Williams @williamsba hYp://www.sitepoint.com/forums/showthread.php?83772-­‐web-­‐site-­‐hacked   My  IntroducLon  to  SQLi  
  12. 12. SQL INJECTION - SQLI Brad Williams @williamsba $wpdb->insert()
  13. 13. 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:  
  14. 14. SQL INJECTION - SQLI Brad Williams @williamsba $wpdb->update()
  15. 15. 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:  
  16. 16. SQL INJECTION - SQLI Brad Williams @williamsba $wpdb->delete()
  17. 17. SQL INJECTION - SQLI Brad Williams @williamsba $wpdb->delete( $wpdb->posts, array( 'ID' => 5 ), array( '%d' ) ); $wpdb->delete() $wpdb->delete( $table, $where, $where_format ) Example:  
  18. 18. SQL INJECTION - SQLI Brad Williams @williamsba $wpdb->prepare()
  19. 19. 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()
  20. 20. 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()
  21. 21. 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  
  22. 22. SQL INJECTION - SQLI Brad Williams @williamsba hYp://xkcd.com/327/   Don’t  be  LiYle  Bobby  Tables  
  23. 23. CROSS-SITE SCRIPTING - XSS Brad Williams @williamsba Cross-­‐Site  ScripLng     (XSS)  
  24. 24. CROSS-SITE SCRIPTING - XSS Brad Williams @williamsba   What  is  Cross-­‐Site  ScripLng?     AYacker  injects  client-­‐side  scripts  into  your  web  pages  
  25. 25. 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  
  26. 26. 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  
  27. 27. CROSS-SITE SCRIPTING - XSS Brad Williams @williamsba <h1><?php echo $title; ?></h1> BAD  
  28. 28. CROSS-SITE SCRIPTING - XSS Brad Williams @williamsba <?php $title = "<script>alert('Hello Europe!');</script>"; ?> <h1><?php echo $title; ?></h1> BAD  
  29. 29. 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('Hello Europe!');&lt;/script&gt;</h1> GOOD  
  30. 30. 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  
  31. 31. 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  
  32. 32. 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  
  33. 33. 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  
  34. 34. 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  
  35. 35. CROSS-SITE SCRIPTING - XSS Brad Williams @williamsba Integers  
  36. 36. 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 ); ?>" />
  37. 37. 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 ); ?>" />
  38. 38. CROSS-SITE SCRIPTING - XSS Brad Williams @williamsba SaniLzing   To  saniLze  is  to  take  the  data  and  clean   to  make  safe  
  39. 39. CROSS-SITE SCRIPTING - XSS Brad Williams @williamsba <?php update_post_meta( 420, '_post_meta_key', $_POST['new_meta_value'] ); ?> BAD  
  40. 40. 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'] ) ); ?>
  41. 41. 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'] ) ); ?>
  42. 42. 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'] ) ); ?>
  43. 43. 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>  
  44. 44. 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  
  45. 45. CROSS-SITE REQUEST FORGERY - CSRF Brad Williams @williamsba Cross-­‐site  Request   Forgery   (CSRF)  
  46. 46. 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)  
  47. 47. CROSS-SITE REQUEST FORGERY - CSRF Brad Williams @williamsba Nonces   AcLon,  object,  &  user  specific  Lme-­‐ limited  secret  keys  
  48. 48. 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  
  49. 49. 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 );
  50. 50. 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  
  51. 51. 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  
  52. 52. 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 );
  53. 53. 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  
  54. 54. CROSS-SITE REQUEST FORGERY - CSRF Brad Williams @williamsba Nonces   Specific  to   • WordPress  User   • AcLon  AYempted   • Object  of  aYempted  acLon   • Time  Window  
  55. 55. 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/    
  56. 56. DRADCAST PLUG Brad Williams @williamsba Listen  to  the  DradCast  WordPress  Podcast                                            LIVE  every  Wednesday  @  8pm  EDT     DradCast.com  
  57. 57. RESOURCES Brad Williams @williamsba #wceu after party Drink  Time!  
  58. 58. CONTACT BRAD Brad Williams @williamsba Brad  Williams   brad@webdevstudios.com     Blog:    strangework.com   TwiYer:  @williamsba       Professional  WordPress   Second  EdiLon  is  OUT!   hYp://bit.ly/prowp2  

×