User Tools

Site Tools


help:sql_injection_sqli

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
help:sql_injection_sqli [2016/10/12 08:23] peterhelp:sql_injection_sqli [2020/07/22 17:55] (current) – old revision restored (2016/10/13 15:20) 207.244.157.10
Line 4: Line 4:
  
 Injection flaws occur when an application sends untrusted data to an interpreter.  Injection flaws are very prevalent, particularly in legacy code.  They are often found in SQL, LDAP, Xpath, or NoSQL queries; OS commands; XML parsers, SMTP Headers, program arguments, etc.  Injection flaws are easy to discover when examining code, but frequently hard to discover via testing.  Scanners and fuzzers can help attackers find injection flaws. Injection flaws occur when an application sends untrusted data to an interpreter.  Injection flaws are very prevalent, particularly in legacy code.  They are often found in SQL, LDAP, Xpath, or NoSQL queries; OS commands; XML parsers, SMTP Headers, program arguments, etc.  Injection flaws are easy to discover when examining code, but frequently hard to discover via testing.  Scanners and fuzzers can help attackers find injection flaws.
 +
 +[[SQL Injection:Basic types of SQL injections|Basic types of SQL injections]]
 +
 +[[SQL Injection:Check if a website is vulnerable to SQL Injection|Check if a website is vulnerable to SQL Injection]]
  
 [[SQL Injection:Example attacks|Example attacks]] [[SQL Injection:Example attacks|Example attacks]]
Line 9: Line 13:
 [[SQL Injection:Primary Defenses|Primary Defenses]] [[SQL Injection:Primary Defenses|Primary Defenses]]
  
-===== Example attacks ===== +[[SQL Injection:What is SQL Injection|What is SQL Injection]]
- +
-**Scenario #1**: The application uses untrusted data in the construction of the following vulnerable SQL call: +
- +
-<code java> +
-String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") + "'"; +
-</code> +
- +
-**Scenario #2**: Similarly, an application’s blind trust in frameworks may result in queries that are still vulnerable, (e.g., Hibernate Query Language (HQL)): +
- +
-<code sql> +
-Query HQLQuery = session.createQuery(“FROM accounts WHERE custID='“ + request.getParameter("id") + "'"); +
-</code> +
- +
-In both cases, the attacker modifies the ‘id’ parameter value in her browser to send: ' or '1'='1.   +
- +
-For example:  http://example.com/app/accountView?id=' or '1'='+
- +
-This changes the meaning of both queries to return all the records from the accounts table.   More dangerous attacks could modify data or even invoke stored procedures. +
- +
-**Scenario #3**:  Code to do an insert into the database could also be vulnerable.   +
- +
-<code sql> +
-$sql = "INSERT INTO Students (Name) VALUES ('" . $studentName . "');"; +
-execute_sql($sql); +
-</code> +
- +
-The first line creates a string containing an SQL INSERT statement. The content of the **$studentName** variable is glued into the SQL statement. The second line sends the resulting SQL statement to the database. The pitfall of this code is that outside data, in this case the content of $studentName, becomes part of the SQL statement. +
- +
-First let's see what the SQL statement looks like if we insert a student named John: +
- +
-<code sql> +
-INSERT INTO Students (Name) VALUES ('John'); +
-</code> +
- +
-This does exactly what we want: it inserts John into the Students table. +
- +
-Now we insert some injection code by setting $studentName to **<nowiki>Robert'); DROP TABLE Students;--</nowiki>**. The SQL statement becomes: +
- +
-<code sql> +
-INSERT INTO Students (Name) VALUES ('Robert'); DROP TABLE Students;--'); +
-</code> +
- +
-This inserts Robert into the Students table. However, the INSERT statement is now followed by a **DROP TABLE** statement which removes the entire Students table. Ouch! +
- +
- +
-===== Primary Defenses ===== +
- +
-  * Use Prepared Statements (Parameterized Queries) +
-  * Use Stored Procedures +
-  * Escape all User Supplied Input +
- +
- +
-===== Prepared Statements ===== +
- +
-The use of prepared statements with variable binding (aka parameterized queries) is how all developers should first be taught how to write database queries.  Parameterized queries force the developer to first define all the SQL code, and then pass in each parameter to the query later.  This coding style allows the database to distinguish between code and data, regardless of what user input is supplied. +
- +
-Prepared statements ensure that an attacker is not able to change the intent of a query, even if SQL commands are inserted by an attacker.  In the safe example below, if an attacker were to enter the userID of tom' or '1'='1, the parameterized query would not be vulnerable and would instead look for a username which literally matched the entire string tom' or '1'='1. +
- +
- +
-==== PHP ==== +
- +
-=== Using mysqli === +
- +
-The MySQL Improved extension handles bound parameters. +
- +
-<code php> +
-$stmt = $db->prepare('update people set name = ? where id = ?'); +
-$stmt->bind_param('si',$name,$id); +
-$stmt->execute(); +
-</code> +
- +
-=== Using ADODB === +
- +
-ADODB provides a way to prepare, bind and execute all in the same method call. +
- +
-<code php> +
-$dbConnection = NewADOConnection($connectionString); +
-$sqlResult = $dbConnection->Execute( +
-    'SELECT user_id,first_name,last_name FROM users WHERE username=? AND password=?', +
-    array($_REQUEST['username'], sha1($_REQUEST['password']+
-); +
-</code> +
- +
- +
-=== Using the ODBC layer === +
- +
-<code php> +
-$stmt = odbc_prepare( $conn, 'SELECT * FROM users WHERE email = ?' ); +
-$success = odbc_execute( $stmt, array($email) ); +
-</code> +
- +
-or: +
- +
-<code php> +
-$res = odbc_exec($conn, 'SELECT * FROM users WHERE email = ?', array($email)); +
-$sth = $dbh->prepare('SELECT * FROM users WHERE email = :email'); +
-$sth->execute(array(':email' => $email)); +
-</code> +
- +
-=== Using the PDO layer === +
- +
-Here's the long way to do bind parameters. +
- +
-<code php> +
-$dbh = new PDO('mysql:dbname=testdb;host=127.0.0.1', $user, $password); +
-$stmt = $dbh->prepare('INSERT INTO REGISTRY (name, value) VALUES (:name, :value)'); +
-$stmt->bindParam(':name', $name); +
-$stmt->bindParam(':value', $value); +
- +
-// insert one row +
-$name = 'one'; +
-$value = 1; +
-$stmt->execute(); +
-</code> +
- +
-And a shorter way to pass things in. +
- +
-<code php> +
-$dbh = new PDO('mysql:dbname=testdb;host=127.0.0.1', $user, $password); +
-$stmt = $dbh->prepare('UPDATE people SET name = :new_name WHERE id = :id'); +
-$stmt->execute( array('new_name' => $name, 'id' => $id) ); +
-</code> +
- +
- +
-=== Using PostgreSQL === +
- +
-<code php> +
-$result = pg_query_params( $dbh, 'SELECT * FROM users WHERE email = $1', array($email) ); +
-</code> +
- +
- +
-==== Java ==== +
- +
-=== JDBC === +
- +
-The JDBC API has a class called PreparedStatement which allows the programmer to safely insert user-supplied data into a SQL query. The location of each input value in the query string is marked with a question mark. The various set*() methods are then used to safely perform the insertion. +
- +
-<code jaVA> +
-String name = //user input +
-int age = //user input +
-Connection connection = DriverManager.getConnection(...); +
-PreparedStatement statement = connection.prepareStatement( +
-        "SELECT * FROM people WHERE lastName = ? AND age > ?" ); +
-statement.setString(1, name); //lastName is a VARCHAR +
-statement.setInt(2, age); //age is an INT +
-ResultSet rs = statement.executeQuery(); +
-while (rs.next()){ +
-    //... +
-+
-</code> +
- +
-=== Hibernate === +
- +
-Hibernate uses named parameters to safely insert data into a query. A named parameter consists of a colon, followed by a unique name for the parameter. +
- +
-<code java> +
-String name = //user input +
-int age = //user input +
-Session session = //... +
-Query query = session.createQuery("from People where lastName = :name and age > :age"); +
-query.setString("name", name); +
-query.setInteger("age", age); +
-Iterator people = query.iterate(); +
-</code> +
- +
- +
-==== Perl ==== +
- +
-Perl's DBI, available on the CPAN, supports parameterized SQL calls. Both the do method and prepare method support parameters ("placeholders", as they call them) for most database drivers. For example: +
- +
-<code perl> +
-$sth = $dbh->prepare("SELECT * FROM users WHERE email = ?"); +
-foreach my $email (@emails) { +
-    $sth->execute($email); +
-    $row = $sth->fetchrow_hashref; +
-    [...] +
-+
-</code> +
- +
-However, you can't use parameterization for identifiers (table names, column names) so you need to use DBI's quote_identifier() method for that: +
- +
-<code perl> +
-# Make sure a table name we want to use is safe: +
-my $quoted_table_name = $dbh->quote_identifier($table_name); +
- +
-# Assume @cols contains a list of column names you need to fetch: +
-my $cols = join ',', map { $dbh->quote_identifier($_) } @cols; +
- +
-my $sth = $dbh->prepare("SELECT $cols FROM $quoted_table_name ..."); +
-</code> +
- +
-You could also avoid writing SQL by hand by using DBIx::Class, SQL::Abstract etc to generate your SQL for you programmatically. +
- +
- +
-==== SQLite ====+
  
-Use **sqlite3_prepare()** to create statement object.+[[SQL Injection:Why not to use escape quotes as defence|Why not to use escape quotes as a defence]]
  
  
-===== References ===== 
  
-http://bobby-tables.com/php.html 
help/sql_injection_sqli.1476260638.txt.gz · Last modified: 2020/07/15 09:30 (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki