Přeskočit na hlavní obsah

Query parametrizace

  • SQL injection je jednou z nejnebezpečnějších webových zranitelností
  • Představuje vážnou hrozbu, protože útočníkovi umožňuje změnit strukturu SQL dotazu, čímž může ukrást, změnit nebo smazat veškerá data
  • Tento dokument je odvozený z cheat sheetu prevence injection

Příklady query parametrizace

  • SQL injection lze nejlépe zabránit parametrizací query dotazů
  • Mnoho frameworků a knihoven často nabízí parametrizaci na straně klienta
  1. Ujistěte se, že query parametrizaci provádíte na serveru

Prepared statements

Java

String custname = request.getParameter("customerName");
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );

Java Hibernate

// HQL
@Entity // declare as entity;
@NamedQuery(
name="findByDescription",
query="FROM Inventory i WHERE i.productDescription = :productDescription"
)
public class Inventory implements Serializable {
@Id
private long id;
private String productDescription;
}

// Use case
// This should REALLY be validated too
String userSuppliedParameter = request.getParameter("Product-Description");
// Perform input validation to detect attacks
List<Inventory> list =
session.getNamedQuery("findByDescription")
.setParameter("productDescription", userSuppliedParameter).list();

// Criteria API
// This should REALLY be validated too
String userSuppliedParameter = request.getParameter("Product-Description");
// Perform input validation to detect attacks
Inventory inv = (Inventory) session.createCriteria(Inventory.class).add
(Restrictions.eq("productDescription", userSuppliedParameter)).uniqueResult();

.NET

String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
OleDbDataReader reader = command.ExecuteReader();
// …
} catch (OleDbException se) {
// error handling
}

ASP .NET

string sql = "SELECT * FROM Customers WHERE CustomerId = @CustomerId";
SqlCommand command = new SqlCommand(sql);
command.Parameters.Add(new SqlParameter("@CustomerId", System.Data.SqlDbType.Int));
command.Parameters["@CustomerId"].Value = 1;

Ruby

insert_new_user = db.prepare "INSERT INTO users (name, age, gender) VALUES (?, ? ,?)"
insert_new_user.execute 'aizatto', '20', 'male'

Ruby Active Records

## Create
Project.create!(:name => 'owasp')
## Read
Project.all(:conditions => "name = ?", name)
Project.all(:conditions => { :name => name })
Project.where("name = :name", :name => name)
## Update
project.update_attributes(:name => 'owasp')
## Delete
Project.delete(:name => 'name')

PHP

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

Cold Fusion

<cfquery name = "getFirst" dataSource = "cfsnippets">
SELECT * FROM #strDatabasePrefix#_courses WHERE intCourseID =
<cfqueryparam value = #intCourseID# CFSQLType = "CF_SQL_INTEGER">
</cfquery>

PERL

my $sql = "INSERT INTO foo (bar, baz) VALUES ( ?, ? )";
my $sth = $dbh->prepare( $sql );
$sth->execute( $bar, $baz );

Uložené procedury

  • SQL napsané v aplikaci není jediným místem, kde může dojít ke vzniku SQL injection
  • Mohou vzniknout také v uložených procedurách (stored procedures), pokud se v nich dynamicky konstruuje SQL
  • Dynamické SQL je také možné parametrizovat pomocí bind proměnných

Oracle PL/SQL

  • Na tomto příkladu není žádné dynamicky vytvořené SQL a není tak potřeba cokoli parametrizovat
PROCEDURE SafeGetBalanceQuery(UserID varchar, Dept varchar) AS BEGIN
SELECT balance FROM accounts_table WHERE user_ID = UserID AND department = Dept;
END;
  • Bind proměnné sdělují databázi, že vstupy jsou dynamické a jde o data, nikoli kód
PROCEDURE AnotherSafeGetBalanceQuery(UserID varchar, Dept varchar)
AS stmt VARCHAR(400); result NUMBER;
BEGIN
stmt := 'SELECT balance FROM accounts_table WHERE user_ID = :1
AND department = :2';
EXECUTE IMMEDIATE stmt INTO result USING UserID, Dept;
RETURN result;
END;

SQL Server - Transact-SQL

  • Stejně jako v předchozím případě, ani zde se nevytváří žádný SQL dotaz dynamicky
PROCEDURE SafeGetBalanceQuery(@UserID varchar(20), @Dept varchar(10)) AS BEGIN
SELECT balance FROM accounts_table WHERE user_ID = @UserID AND department = @Dept
END
  • Parametrizovaný Transact-SQL dotaz
PROCEDURE SafeGetBalanceQuery(@UserID varchar(20), @Dept varchar(10)) AS BEGIN
DECLARE @sql VARCHAR(200)
SELECT @sql = 'SELECT balance FROM accounts_table WHERE '
+ 'user_ID = @UID AND department = @DPT'
EXEC sp_executesql @sql,
'@UID VARCHAR(20), @DPT VARCHAR(10)',
@UID=@UserID, @DPT=@Dept
END

Kam dál

Zranitelnosti

Checklisty