Your SlideShare is downloading. ×
Sql Injection Myths and Fallacies
Upcoming SlideShare
Loading in...5

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Sql Injection Myths and Fallacies


Published on

The most massive crime of identity theft in history was perpetrated in 2007 by exploiting an SQL Injection vulnerability. This issue is one of the most common and most serious threats to web application security. In this presentation, you'll see some common myths busted and you'll get a better understanding of defending against SQL injection.

Published in: Technology
  • While I agree with the limitations of parameters (can't be used for table names, ordering etc) it feels like it's a different level of 'not a fix' to the others (such as escaping). Unless I'm wrong - and I'm *not* a database expert - query parameters really are *the* way to go in situations where they're applicable (i.e. when you don't need to dynamically choose the table name, build a list etc). There aren't all the 'gotchas' to be really careful with that there are with escaping (which always feels like a losing battle to me).

    Of course there are other benefits of query parameters anyway - simpler to read SQL and avoiding error-prone conversions (especially for date/time types) for example.

    Is this a fair statement, or are there downsides to query parameters beyond the limitations? The good part of the limitations is that when you bump into them, you *know* you've bumped into them, because the query simply doesn't work - so with query parameters you're either working safely, or you're broken. Again, that's assuming I'm not missing something.
    Are you sure you want to  Yes  No
    Your message goes here
  • the 20th slide, story of my life
    Are you sure you want to  Yes  No
    Your message goes here
  • very good
    Are you sure you want to  Yes  No
    Your message goes here
  • Awesome PPT and very knowledgeable
    Are you sure you want to  Yes  No
    Your message goes here
  • Slide 27 - Why does QueryAnyTable have a table_name IN parameter when we pass the 'SELECT * FROM' to the procedure? Won't that execute 'SELECT * FROM SELECT * FROM ...' ?
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

No notes for slide


  • 1. SQL InjectionMyths and Fallacies Bill Karwin, Percona Inc.
  • 2. Me• Software developer• C, Java, Perl, PHP, Ruby• SQL maven• Percona Consultant and Trainer• Author of SQL Antipatterns: Avoiding the Pitfalls of Database Programming
  • 3. What is SQL Injection? * FROM Bugs WHERE bug_id = $_GET[bugid] user input
  • 4. What is SQL Injection? OR TRUESELECT * FROM Bugs WHERE bug_id = 1234 OR TRUE unintended logic
  • 5. Worse SQL Injection &pass=xyzzyUPDATE Accounts SET password = SHA2($password) WHERE account_id = $account_id
  • 6. Worse SQL Injection OR TRUE &pass=xyzzy), admin=(1 changes account to administratorUPDATE Accounts SET password = SHA2(xyzzy), admin=(1) WHERE account_id = 1234 OR TRUE changes password for all accounts
  • 7. Myths and Fallacies MYTH Based on a grain of truth, but derives a wrong conclusionFALLACY Based on a false assumption, but derives a logical conclusion
  • 8. Myth MYTH“SQL Injection is an oldproblem―so I don’t have to worry about it.”
  • 9. Identity Theft• 130 million credit card numbers• Albert Gonzalez used SQL Injection to install his code onto credit-card servers• Sentenced 20 years in March 2010• Cost to victim company Heartland Payment Systems: $12.6 million • •
  • 10. Ruby on Rails 3.x• June 1, 2012.• Ruby on Rails 3.2.5 releases fix for a critical SQL injection vulnerability.• Applications using ActiveRecord in Ruby on Rails 3.0 and later were vulnerable.• Fixes released in RoR 3.1.5 and 3.0.13 as well.•
  • 11.• June 4, 2012.• Russian hackers posted 6.5 million user credentials acquired from• The means of attack is still unconfirmed, but...• A class action lawsuit against LinkedIn over this breach alleges that the attackers exploited an SQL injection vulnerability.•
  • 12. Yahoo! Voices• July 12, 2012.• 453,000 email addresses and passwords leaked.• The perpetrators claimed they exploited union-based SQL injection.••
  • 13. Myth MYTH “Escaping inputprevents SQL injection.”
  • 14. Escaping & Filtering OR TRUE &pass=xyzzy), admin=(1 backslash escapes special charactersUPDATE Accounts SET password = SHA2(xyzzy), admin=(1) WHERE account_id = 1234 coerced to integer
  • 15. Escaping & Filtering Functions<?php$password = $_POST["password"]; $password_escaped = mysql_real_escape_string($password);$id = (int) $_POST["account"];$sql = "UPDATE Accounts SET password = SHA2(‘{$password_escaped}’) WHERE account_id = {$id}";mysql_query($sql);
  • 16. Escaping & Filtering Functions<?php$password = $_POST["password"]; $password_quoted = $pdo->quote($password);$id = filter_input(INPUT_POST, "account", FILTER_SANITIZE_NUMBER_INT);$sql = "UPDATE Accounts SET password = SHA2( {$password_quoted} ) WHERE account_id = {$id}";$pdo->query($sql);
  • 17. Identifiers and Keywords<?php no API to support delimited identifiers$column = $_GET["order"]; $column_delimited = $pdo->FUNCTION?($column);$direction = $_GET["dir"];$sql = "SELECT * FROM Bugs ORDER BY {$column_delimited} {$direction}";$pdo->query($sql); keywords get no quoting
  • 18. Myth MYTH“If some escaping is good, more must be better.”
  • 19. Overkill?<?php real function from a user’s projectfunction sanitize($string){ $string = strip_tags($string); $string = htmlspecialchars($string); $string = trim(rtrim(ltrim($string))); $string = mysql_real_escape_string($string); return $string; }$password = sanitize( $_POST["password"] );mysql_query("UPDATE Users SET password = $password WHERE user_id = $user_id");
  • 21. Just the One Will Do<?php$password = mysql_real_escape_string( $_POST["password"] );mysql_query("UPDATE Users SET password = $password WHERE user_id = $user_id");
  • 22. Myth MYTH“I can write my own escaping function.”
  • 23. Please Don’t• addslashes() isn’t enough in a multibyte world• Example: • OR x=x • $account = addslashes($_REQUEST(“account”)); • Function sees a single-quote (%27) and inserts backslash (%5c). Result: %bf%5c%27 OR x=x single-quote valid multi-byte character in GBK:
  • 24. Grant Access to Any Account• Interpolating: SELECT * FROM Accounts WHERE account = {$account} AND password = {$passwd}• Results in: SELECT * FROM Accounts WHERE account = OR x= x AND password = xyzzy • •
  • 25. Solutions• Use driver-provided escaping functions: • mysql_real_escape_string() • mysqli::real_escape_string() • PDO::quote()• Use API functions to set the client character set: • mysql_set_charset() • mysqli::set_charset() •• Use UTF-8 instead of GBK, SJIS, etc.
  • 26. Myth MYTH“Unsafe data comes fromusers―if it’s already in the database, then it’s safe.”
  • 27. Not Necessarily$sql = "SELECT product_name FROM Products"; $prodname = $pdo->query($sql)->fetchColumn();$sql = "SELECT * FROM Bugs WHERE MATCH(summary, description) AGAINST ({$prodname})"; not safe input
  • 28. Fallacy FALLACY“Using stored procedures prevents SQL Injection.”
  • 29. Static SQL in Procedures filtering by data type is a good thingCREATE PROCEDURE FindBugById (IN bugid INT) BEGIN SELECT * FROM Bugs WHERE bug_id = bugid; ENDCALL FindByBugId(1234)
  • 30. Dynamic SQL in ProceduresCREATE PROCEDURE BugsOrderBy (IN column_name VARCHAR(100), IN direction VARCHAR(4)) BEGIN interpolating arbitrary SET @query = CONCAT( strings = SQL injection SELECT * FROM Bugs ORDER BY , column_name, , direction); PREPARE stmt FROM @query; EXECUTE stmt; ENDCALL BugsOrderBy(date_reported, DESC)
  • 31. Worthy of TheDailyWTFCREATE PROCEDURE QueryAnyTable (IN table_name VARCHAR(100)) BEGIN SET @query = CONCAT( SELECT * FROM , table_name); PREPARE stmt FROM @query; EXECUTE stmt; ENDCALL QueryAnyTable( (SELECT * FROM ...) )
  • 32. Myth MYTH“Conservative SQL privileges limit the damage.”
  • 33. Denial of ServiceSELECT * FROM Bugs JOIN Bugs JOIN Bugs JOIN Bugs JOIN Bugs JOIN Bugs 100 bugs = 1 trillion rows
  • 34. Denial of ServiceSELECT * FROM Bugs JOIN Bugs JOIN Bugs JOIN Bugs JOIN Bugs JOIN Bugs ORDER BY 1 still requires only SELECT privilege
  • 35. Just Asking for It query=SELECT%20*%20FROM %20Bugs
  • 36. Fallacy FALLACY “It’s just an intranetapplication―it doesn’t need to be secure.”
  • 37. Just Ask This Manager
  • 38. What Stays on the Intranet?• You could be told to give business partners access to an internal application UPDATE Accounts SET password = SHA2($password) WHERE account_id = $account_id
  • 39. What Stays on the Intranet?• Your casual code could be copied & pasted into external applications UPDATE Accounts UPDATE Accounts SET password = SET password = SHA2($password) SHA2($password) WHERE account_id WHERE account_id = $account_id = $account_id
  • 40. What Stays on the Intranet?• It’s hard to argue for a security review or rewrite for a “finished” application $$ $ ? UPDATE Accounts SET password = SHA2($password) WHERE account_id = $account_id
  • 41. Myth MYTH “My frameworkprevents SQL Injection.”
  • 42. ORMs Allow Custom SQL• Dynamic SQL always risks SQL Injection, for example Rails ActiveRecord: Bugs.all( :joins => "JOIN Accounts ON reported_by = account_id", any custom SQL can carry SQL injection :order => "date_reported DESC" )
  • 43. Whose Responsibility?• Security is the application developer’s job• No database, connector, or framework can prevent SQL injection all the time
  • 44. Fallacy FALLACY“Query parameters do quoting for you.”
  • 45. Interpolating Dynamic Values• Query needs a dynamic value: SELECT * FROM Bugs WHERE bug_id = $_GET[bugid] user input
  • 46. Using a Parameter• Query parameter takes the place of a dynamic value: SELECT * FROM Bugs WHERE bug_id = ? parameter placeholder
  • 47. How the Database Parses It SELECT expr-list * simple- bugsquery FROM table bug_id WHERE expr equality = ? parameter placeholder
  • 48. How the Database Executes It SELECT expr-list * simple- bugsquery FROM table bug_id WHERE expr equality = 1234 parameter value
  • 49. Interpolation SELECT expr-list * bug_id simple- bugsquery FROM table equality = 1234 WHERE expr OR TRUE SQL injection
  • 50. Parameterization SELECT expr-list * simple- bugsquery FROM table bug_id WHERE expr equality = 1234 OR TRUE no parameter can change the tree
  • 51. Sequence of Prepare & Execute Client Server prepare query convert to machine- send SQL readable form parse query optimize query execute query send parameters repeat with bind parameters different parameters execute query return results
  • 52. Myth MYTH“Query parameters prevent SQL Injection.”
  • 53. One Parameter = One ValueSELECT * FROM Bugs WHERE bug_id = ?
  • 54. Not a List of ValuesSELECT * FROM Bugs WHERE bug_id IN ( ? )
  • 55. Not a Table NameSELECT * FROM ? WHERE bug_id = 1234
  • 56. Not a Column NameSELECT * FROM Bugs ORDER BY ?
  • 57. Not an SQL KeywordSELECT * FROM Bugs ORDER BY date_reported ?
  • 58. Interpolation vs. ParametersScenario Example Value Interpolation Parametersingle value ‘1234’ SELECT * FROM Bugs SELECT * FROM Bugs WHERE bug_id = $id WHERE bug_id = ?multiple ‘1234, 3456, 5678’ SELECT * FROM Bugs SELECT * FROM Bugsvalues WHERE bug_id IN ($list) WHERE bug_id IN ( ?, ?, ? )table name ‘Bugs’ SELECT * FROM $table NO WHERE bug_id = 1234column name ‘date_reported’ SELECT * FROM Bugs NO ORDER BY $columnother syntax ‘DESC’ SELECT * FROM Bugs NO ORDER BY date_reported $direction
  • 59. Solution SOLUTIONWhitelist Maps
  • 60. Example SQL Injection order=date_reported&dir=ASC<?php unsafe inputs$sortorder = $_GET["order"]; $direction = $_GET["dir"]; SQL Injection$sql = "SELECT * FROM Bugs ORDER BY {$sortorder} {$direction}";$stmt = $pdo->query($sql);
  • 61. Fix with a Whitelist Map application SQL identifiers request values and keywords<?php$sortorders = array("DEFAULT" => "bug_id", "status" => "status", "date" => "date_reported" );$directions = array( "DEFAULT" => "ASC", "up" => "ASC", "down" => "DESC" );
  • 62. Map User Input to Safe SQL<?phpif (isset( $sortorders[ $_GET["order"] ])) { $sortorder = $sortorders[ $_GET["order"] ]; } else { $sortorder = $sortorders["DEFAULT"]; }
  • 63. Map User Input to Safe SQL PHP 5.3 syntax<?php$direction = $directions[ $_GET["dir"] ] ?: $directions["DEFAULT"];
  • 64. Interpolate Safe SQL<?php whitelisted values$sql = "SELECT * FROM Bugs ORDER BY {$sortorder} {$direction}";$stmt = $pdo->query($sql);
  • 65. Benefits of Whitelist Maps• Protects against SQL injection in cases where escaping and parameterization doesn’t help.• Decouples web interface from database schema.• Uses simple, declarative technique.• Works independently of any framework.
  • 66. Fallacy FALLACY “Queries parametershurt SQL performance.”
  • 67. Simple Query Profiled Elapsed 0.004 0.003 0.002 0.001MySQL MySQLi MySQLi Prep 0 PDO PDO Prep
  • 68. Complex Query Profiled Elapsed 1.56 1.17 0.78 0.39MySQL MySQLi MySQLi Prep 0 PDO PDO Prep
  • 69. Myth MYTH“A proxy/firewall solution prevents SQL injection.”
  • 70. Oracle Database Firewall• Reverse proxy between application and Oracle • Whitelist of known SQL queries • Learns legitimate queries from application traffic • Blocks unknown SQL queries • Also supports Microsoft SQL Server, IBM DB2, Sybase ASE, SQL Anywhere•
  • 71. GreenSQL• Reverse proxy for MySQL, PostgreSQL, Microsoft SQL Server• Detects / reports / blocks “suspicious” queries: • Access to sensitive tables • Comments inside SQL commands • Empty password • An ‘or’ token inside a query • An SQL expression that always returns true•
  • 72. Still not Perfect• Vipin Samar, Oracle vice president of Database Security: • “Database Firewall is a good first layer of defense for databases but it wont protect you from everything,” •• GreenSQL Architecture • “GreenSQL can sometimes generate false positive and false negative errors. As a result, some legal queries may be blocked or the GreenSQL system may pass through an illegal query undetected.” •
  • 73. Limitations of Proxy Solutions• False sense of security; discourages code review• Gating factor for emergency code deployment• Constrains application from writing dynamic SQL• Doesn’t stop SQL injection in Stored Procedures
  • 74. Fallacy FALLACY “NoSQL databases areimmune to SQL injection.”
  • 75. “NoSQL Injection”<?php any string-interpolation$map = new MongoCode("function() { of untrusted content emit(this." . $_GET["column"] . ",1); is Code Injection } ");$data = $db->command( array( "mapreduce" => "Users", "map" => $map ) );
  • 76. NoSQL Injection in the Wild• Diaspora wrote MongoDB map/reduce functions dynamically from Ruby on Rails: • def Person.all($where => "function() { return this.diaspora_handle.match(/^#{query}/i) || this.profile.first_name.match(/^#{query}/i) || this.profile.last_name.match(/^#{query}/i); }") end did query come from • a trusted source?
  • 77. Myths and Fallacies• I don’t have to worry anymore • My app doesn’t need security• Escaping is the fix • Frameworks are the fix• More escaping is better • Parameters quote for you• I can code an escaping • Parameters are the fix function • Parameters make queries slow• Only user input is unsafe • SQL proxies are the fix• Stored procs are the fix • NoSQL databases are the fix• SQL privileges are the fix there is no single silver bullet— use all defenses when appropriate
  • 78. SQL Antipatterns
  • 79. New York, October 1-2, 2012London, December 3-4, 2012Santa Clara, April 22-25, 2013
  • 80. License and Copyright Copyright 2010-2012 Bill Karwin Released under a Creative Commons 3.0 License: You are free to share - to copy, distribute and transmit this work, under the following conditions: Attribution. Noncommercial. No Derivative Works.You must attribute this work You may not use this work You may not alter, transform, to Bill Karwin. for commercial purposes. or build upon this work.