Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.



Published on

This talk describes SQL injection and how to avoid it.

Published in: Technology
  • Be the first to comment


  1. 1. Detecting (and even preventing) SQL InjectionUsing the Percona Toolkit and Noinject!Justin SwanhartPercona Live, April 2013
  3. 3. Introduction• Who am I?• What do I do?• Why am I here?3
  4. 4. The tools• MySQL (5.0+)• Percona Toolkit– pt-query-digest– pt-fingerprint• MySQL Proxy (0.8.0+)• Apache and PHP 5.3+4
  6. 6. What is SQL injection?• SQL injection is an attack vector– An attacker modifies the SQL queries which will beexecuted by the server– But the attacker does not need to change the codeon the server or get access to the server6
  7. 7. What is SQL injection – interpolation (strings)$username = $_GET[‘username’];$sql =“select 1from users.userswhere admin_flag=trueand username = ‘“ . $username . “’”;$ wget http://host/path.php?username=bob$ wget http://host/path.php?user_id=“ or 1=1” and username = ‘’ or ‘1’ = ‘1’7SQL injection!
  8. 8. Escape strings, or use prepared statements!#escape string values$username = mysqli_real_escape_string($_GET[‘username’]);$sql = “select … and username = ‘“ . $username . “’”;#prepared statement$username = GET[‘username’];$stmt = mysqli_stmt_init($conn);$sql = “select … and username = ?”mysqli_stmt_prepare($stmt, $sql);mysqli_stmt_bind_param($stmt, “s”, $username);mysqli_stmt_execute($stmt);mysqli_stmt_close($stmt);8
  9. 9. What is SQL injection – interpolation (ints)$user_id = $_GET[‘user_id’];$sql =“select 1from users.userswhere admin_flag=trueand user_id = “ . $user_id;…$ wget http://host/path.php?user_id=1$ wget http://host/path.php?user_id=“1 or 1=1”9SQL injection!
  10. 10. Use type checking, or prepared statements!#check that integers really are integers!$user_id = GET[‘user_id’];if(!is_numeric(user_id)) $user_id = “NULL”;$sql = “select … and user_id = “ . $user_id;#prepared statement$user_id = GET[‘user_id’];$sql = “select … and user_id = ?”…mysqli_stmt_bind_param($stmt, “i”, $user_id);mysqli_stmt_execute($stmt);10
  11. 11. When escaping can’t help• Some parts of a SQL statement can’t bemanipulated using parameters• These include– ORDER BY columns– Variable number of items in an IN list– Adding SQL syntax like DISTINCT11
  12. 12. Don’t use user input in the query#avoid using user input directly in ANY way$sql = “select * from listings where deleted = 0 and sold= 0 and open = 1”;if(!empty($_GET[‘ob’])) {$sql .= “ ORDER BY “ . $_GET[‘ob’];}wget … ?ob=post_datewget … ?ob=“post_date union all (select * from listings)”12Now we can see all listingsBad!
  13. 13. Use whitelisting instead#avoid using user input directly in ANY way$sql = “select * from listings where deleted = 0 and sold= 0 and open = 1”;$allowed = array(‘post_date’,’neighborhood’,’etc’);if(!empty($_GET[‘ob’]) && is_string($_GET[‘ob’])) {if(in_array($_GET[‘ob’], $allowed)) {$sql .= “ ORDER BY “ . $_GET[‘ob’];}}wget … ?ob=post_datewget … ?ob=“post_date union all (select * from listings)”13in_array() is the keeper of the gate
  14. 14. All that works great for the apps you control• BUT…– If you don’t have the source for an app, then youreally can’t be sure it isn’t safe from SQL injection– Or maybe you have to support old apps– Or apps that were not developed rigorously– What do we do in these cases?14
  15. 15. SQL INJECTION DETECTION USINGPT-QUERY-DIGESTOut-of-band SQL injection detection15
  16. 16. How to detect SQL injection?• Most applications only do a small number ofthings.– Add orders, mark orders as shipped, updateaddresses, etc.– The SQL “patterns” that identify these behaviorscan be collected and whitelisted.– Queries that don’t match a known fingerprint maybe investigated as SQL injection attempts16
  17. 17. What is a query fingerprint?• A query fingerprinting algorithm transforms aquery into a form that allows like queries to begrouped together and identified as a unit– In other words, these like queries share afingerprint– Even though the queries differ slightly they stillfingerprint to the same value– This is a heuristic based approach17
  18. 18. Tools that support query fingerprints• Percona Toolkit tools– pt-query-digest– pt-fingerprint18Reads slow query logs andpopulates the whitelist table.Can also be used to display newqueries that have not beenmarked as allowed.Takes a query (or queries) andproduces fingerprints.Useful for third party tools thatwant to use fingerprints.
  19. 19. What is a query fingerprint (cont?)select * from some_table where col = 3becomesselect * from some_table where col = ?select * from some_table where col = IN (1,2)becomesselect * from some_table where col IN (?)19
  20. 20. Query fingerprints expressed as hashespt-query-digest can provide short hashes ofchecksumsselect * from some_table where col = ?982e5737f9747a5d (1631105377)select * from some_table where col = IN (?)2da8ed487cdfc1c8 (1680229806268)20base 10
  21. 21. pt-query-digest• Normally used for profiling slow queries• Has a “SQL review” feature for DBAs– Designed to mark query fingerprints as havingbeen reviewed– This feature can be co-opted to discover newquery fingerprints automatically– New fingerprints are either new application codeor SQL injection attempts21
  22. 22. pt-query-digest – review feature• Need to store the fingerprints in a table– Known good fingerprints will be marked asreviewed– If pt-query-digest discovers new fingerprints youwill be alerted because there will be unreviewedqueries in the table22
  23. 23. pt-query-digest - review table initializationNeed to initialize the tablept-query-digest /path/to/slow.log --create-review-table--review “h=,P=3306,u=percona,p=2un1c0rns,D=percona,t=whitelist” --sample 1 --no-report23Where to store fingerprintsDon’t waste time on statsDon’t printreport
  24. 24. pt-query-digest – command-line reviewpt-query-digest /path/to/slow.log --review “DSN…” --sample 1 --report --limit 024Ensure that all unreviewed queries are shownDisplay the report of queriesDon’t collect stats, just sample one ofeach new fingerprintHow it knows which queries have alreadybeen reviewed
  26. 26. Detecting new query fingerprintsSELECT count(*)FROM percona.whitelistWHERE reviewed_by IS NULL;SELECT checksum, sampleFROM percona.whitelistWHERE reviewed_by IS NULL;26Any new queries?percona.whitelist is justan example name, you canuse any you likeGet a list of thequeries
  27. 27. Add a query fingerprint to the whitelistUPDATE percona.whitelistSET reviewed_by = ‘allow’,reviewed_on = now()WHERE checksum= 1680229806268;27
  28. 28. Blacklist a query fingerprintYou might also explicitly blacklist a fingerprintUPDATE percona.whitelistSET reviewed_by = ‘deny’,reviewed_on = now()WHERE checksum = 1631105377;28
  29. 29. Web interface for whitelist management• The Noinject! project (discussed later) has aweb interface that can be used to markqueries as reviewed• It can be with both the noinject.lua proxyscript or with pt-query-digest29
  30. 30. LIMITATIONS AND CAVEATSOut of band detection30
  31. 31. Out-of-band detection• Some damage or information leakage mayhave already happened• To limit the extent of the damage send an alertas soon as a new pattern is detected– Ensure thorough application pattern detection in atest environment to avoid false positives31
  32. 32. Get logs as fast as possible• Use tcpdump on a mirrored server port– Pipe the output to pt-query-digest• Use tcpdump on the database server– Adds some additional overhead from running thetools on the same machine– Possibly higher packet loss• Collect and process slow query logs frequently– Adds slow query log overhead to server– Longer delay before processing32
  33. 33. FINDING THE VULNERABILITYWhat to do BEFORE a fishy fingerprint appears33
  34. 34. Prepare for finding a vulnerability• Tracking down the vulnerable code fragmentcan be difficult if you have only the SQLstatement• Not just a problem with SQL injection since it isusually convenient to see where a SQLstatement was generated from34
  35. 35. Add tracing comments to queries• A good approach is to modify the data accesslayer (DAL) to add SQL comments– Comments are preserved in the slow query log– Comments are displayed in SHOW commands• SHOW ENGINE INNODB STATUS• SHOW PROCESSLIST– Make sure your client does not strip comments!35
  36. 36. Add tracing information• PHP can use debug_backtrace() for example• PERL has variables that point to the file andline• Investigate the debugging section of yourlangauge’s manual36
  37. 37. What to place in the comment• Here are some important things to considerplacing into the tracing comment– session_id (or important cookie info)– application file name, and line number– important GET, POST, PUT or DELETE contents– Any other important information which could beuseful for tracking down the vector being used inan attack37
  38. 38. Example comments in SQL queriesselect airport_name, count(*)from dim_airportjoin ontime_facton dest_airport_id = airport_idwhere depdelay > 30and flightdate_id = 20080101/*webserver:,file:show_delays.php,line:326,function:get_delayed_flights,user:justin,sessionid:7B7N2PCNIOKCGF*/38This comment contains all that you need
  39. 39. Most apps don’t do this out of the box• You can modify the application– If you have the source code (and it uses a DAL)• BUT…– There isn’t much you can do if• The application is closed source , or you can’t changethe source• There is no DAL (code/query spaghetti)• For any other reason it is problematic to injectinformation into all SQL queries39
  40. 40. If I can’t change the source?• You can’t fix the problems when you detectthem.• Consider using an open source solution• Or consider in-band protection40
  41. 41. SQL INJECTION PREVENTIONIn-band SQL injection detection41
  42. 42. In-band protection• Using pt-query-digest to discover new querypatterns is useful– But it doesn’t work in real time– It can’t block bad queries from actually executing42
  43. 43. In-band protection• What is needed is a “man in the middle” thatinspects each query to ensure it matches anallowed fingerprint.– MySQL proxy can be used for this purpose43
  44. 44. MySQL Proxy• MySQL Proxy– Supports Lua scripting for easy development– Adds some latency to all queries– Considered “alpha” quality though for simplescripts it seems stable enough– Fingerprinting and checking database also addslatency. 3ms – 5ms per query is to be expected44
  45. 45. Noinject! – The Lua script and PHP interface•• The Lua script for MySQL proxy is pretty muchdrop-in.– Just modify it to point to your database server andspecify credentials and other options.• PHP script is similarly easy to configure.– Drop in a directory on an Apache box– Modify the script to set the options.45
  46. 46. The Lua proxy script – known queries• By default the script will retrieve all knowngood fingerprints and cache them locally whenthe first query is received from a client• Also by default, all queries that fail to pass theknown whitelist check are logged in anexception table.46Both of these options can be changedeasily
  47. 47. The Lua proxy script – known queries• Each query is fingerprinted– If the fingerprint is on the whitelist, the actualquery is sent to the server– If the query is not on the whitelist the behaviorvaries depending on the proxy mode47
  48. 48. Lua script – Proxy mode• permissive mode– Records the SQL fingerprint into the whitelist tablebut does not mark it as reviewed– Allows the query to proceed• restrictive mode– Records the SQL fingerprint into the whitelist table– Returns an empty set for the query48
  49. 49. Why use permissive mode?• Permissive mode allows the collection of SQLfingerprints for an application dynamically– Just run the application with typical workload andthe SQL queries will be recorded automatically– Eventually switch to restrictive mode49
  50. 50. PHP Web interface• 1999 mode HTML interface 50Query SampleLast action timewith noteWhite orblack listthe fingerprint
  51. 51. If you want something prettier• This is open source so…• If you want bug fixes or have feature requests– You can engage with Percona for development– You can contribute!– You can fork your own version 51
  52. 52. If the proxy overhead is too high• You could develop the functionality in MySQL– too bad the parser is not pluggable • Try mysqlnd plugins– fingerprint queries in PHP– match them to a whitelist maintained in a serializedPHP array– reject queries that aren’t approved• Improve the proxy lua script– fingerprint process could probably be made faster52
  53. 53. Percona Training Advantage• This presentation and the Noinject! tool werecreated by Justin Swanhart, one of Percona’sexpert trainers– Check out for a list oftraining events near you– Request training directly by Justin or any of ourother expert trainers by contacting your Perconasales rep today53
  54. 54. 54Q/A