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
- 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