Writing Secure Plugins — WordCamp New York 2009

7,607 views

Published on

How to write secure plugins, from my presentation at WordCamp New York 2009.

Published in: Technology, Business

Writing Secure Plugins — WordCamp New York 2009

  1. 1. Writing Secure Plugins Mark Jaquith @markjaquith markjaquith.com coveredwebservices.com Saturday, November 14, 2009
  2. 2. XSS privilege shell execution escalation CSRF SQL injection Saturday, November 14, 2009
  3. 3. Plugin security is hit-or-miss Saturday, November 14, 2009
  4. 4. Mostly miss Saturday, November 14, 2009
  5. 5. SQL Injection Saturday, November 14, 2009
  6. 6. <?php $wpdb->query( "UPDATE $wpdb->posts SET post_title = '$newtitle' WHERE ID = $my_id" ); ?> Saturday, November 14, 2009
  7. 7. <?php $newtitle = esc_sql( $newtitle ); $my_id = absint( $my_id ); $wpdb->query( "UPDATE $wpdb->posts SET post_title = '$newtitle' WHERE ID = $my_id" ); ?> Saturday, November 14, 2009
  8. 8. $wpdb->update() Saturday, November 14, 2009
  9. 9. <?php $wpdb->update( $wpdb->posts, array( 'post_title' => $newtitle ), array( 'ID' => $my_id ) ); ?> Saturday, November 14, 2009
  10. 10. $wpdb->insert() Saturday, November 14, 2009
  11. 11. <?php $wpdb->insert( $wpdb->posts, array( 'post_title' => $newtitle ) ); ?> Saturday, November 14, 2009
  12. 12. <?php $wpdb->update( $wpdb->posts, array( 'post_title' => $newtitle, 'post_content' => $newcontent ), array( 'ID' => $my_id, 'post_title' => $old_title ) ); ?> Saturday, November 14, 2009
  13. 13. <?php $post_title = 'New Title'; $wheres['ID'] = 123; $wheres['post_title'] = 'Old Title'; $wpdb->update( $wpdb->posts, compact( 'post_title' ), $wheres ); ?> Saturday, November 14, 2009
  14. 14. $wpdb->prepare() Saturday, November 14, 2009
  15. 15. <?php $title = 'Post Title'; $ID = 123; $content = $wpdb->get_var( $wpdb->prepare( "SELECT post_content FROM $wpdb->posts WHERE post_title = %s AND ID = %d", $title, $ID ) ); ?> Saturday, November 14, 2009
  16. 16. •Uses sprintf() formatting •%s for strings •%d for integers •You should not quote or escape Saturday, November 14, 2009
  17. 17. Escape late Saturday, November 14, 2009
  18. 18. XSS Saturday, November 14, 2009
  19. 19. <h1> <?php echo $title; ?> </h1> Saturday, November 14, 2009
  20. 20. <?php $title = '<script> pwnage(); </script>' ?> <h1> <?php echo $title; ?> </h1> Saturday, November 14, 2009
  21. 21. Anything that isn’t hardcoded is suspect Saturday, November 14, 2009
  22. 22. Better: Everything is suspect Saturday, November 14, 2009
  23. 23. Saturday, November 14, 2009
  24. 24. esc_html() Saturday, November 14, 2009
  25. 25. <?php $title = '<script> pwnage(); </script>' ?> <h1> <?php echo esc_html( $title ); ?> </h1> Saturday, November 14, 2009
  26. 26. <?php $title = '" onmouseover="pwnd();'; ?> <a href="#wordcamp" title=" <?php echo $title; ?> "> Link Text </a> Saturday, November 14, 2009
  27. 27. esc_attr() Saturday, November 14, 2009
  28. 28. <?php $title = '" onmouseover="pwnd();'; ?> <a href="#wordcamp" title=" <?php echo esc_attr( $title ); ?> "> Link Text </a> Saturday, November 14, 2009
  29. 29. <?php $url = 'javascript:pwnage();'; ?> <a href=" <?php echo esc_attr( $url ); ?> "> WRONG Link Text </a> Saturday, November 14, 2009
  30. 30. esc_url() Saturday, November 14, 2009
  31. 31. <?php $url = 'javascript:pwnage();'; ?> <a href=" <?php echo esc_url( $url ); ?> "> Link Text </a> Saturday, November 14, 2009
  32. 32. esc_url_raw(), sister of esc_url() Saturday, November 14, 2009
  33. 33. esc_ js() Saturday, November 14, 2009
  34. 34. <script> var foo = '<?php echo esc_js( $bar ); ?>'; </script> Saturday, November 14, 2009
  35. 35. CSRF Saturday, November 14, 2009
  36. 36. Authorization vs. Intention Saturday, November 14, 2009
  37. 37. Nonces action-, object-, user-specific time limited secret keys Saturday, November 14, 2009
  38. 38. Specific to •WordPress user •Action attempted •Object of attempted action •Time window Saturday, November 14, 2009
  39. 39. wp_nonce_field() Saturday, November 14, 2009
  40. 40. <form action="process.php" method="post"> <?php wp_nonce_field('plugin-action_object'); ?> ... </form> Saturday, November 14, 2009
  41. 41. check_admin_referer( ) Saturday, November 14, 2009
  42. 42. <?php // before output goes to browser check_admin_referer('plugin- action_object'); ?> Saturday, November 14, 2009
  43. 43. Still need to use current_user_can() Saturday, November 14, 2009
  44. 44. AJAX CSRF Saturday, November 14, 2009
  45. 45. • wp_create_nonce( 'your_action' ); • &_ajax_nonce=YOUR_NONCE • check_ajax_referer( 'your_action' ); Saturday, November 14, 2009
  46. 46. Privilege Escalation Saturday, November 14, 2009
  47. 47. current_user_can() Saturday, November 14, 2009
  48. 48. Set your salts! http://api.wordpress.org/secret-key/1.1/ Saturday, November 14, 2009
  49. 49. Stupid shit I see all the time Saturday, November 14, 2009
  50. 50. exec() Saturday, November 14, 2009
  51. 51. <form action="<?php echo $_SERVER['REQUEST_URI']; ?>"> Saturday, November 14, 2009
  52. 52. <a href="<?php echo $url; ?>" title="<?php echo $title; ?>"> <?php echo $text; ?> </a> <script> var foo = '<?php echo $js; ?>'; </script> Saturday, November 14, 2009
  53. 53. <a href="<?php echo esc_url( $url ); ?>" title="<?php echo esc_attr( $title ); ?>"> <?php echo esc_html( $text ); ?> </a> <script> var foo = '<?php echo esc_js( $js ); ?>'; </script> Saturday, November 14, 2009
  54. 54. Discussion Saturday, November 14, 2009

×