SQL 注入
SQL 注入
SQL 注入是一种代码注入技术,可能会破坏您的数据库。
SQL 注入是最常见的网络黑客技术之一。
SQL 注入是在 SQL 语句中通过网页输入放置恶意代码。
网页中的 SQL
SQL 注入通常发生在您要求用户输入信息(如用户名/用户 ID)时,用户提供的不是姓名/ID,而是一个您将**无意中**在数据库上运行的 SQL 语句。
请看下面的示例,它通过向选择字符串添加一个变量 (txtUserId) 来创建一个 SELECT
语句。该变量是从用户输入 (getRequestString) 中获取的。
示例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
本章的其余部分描述了在 SQL 语句中使用用户输入的潜在危险。
基于 1=1 始终为真的 SQL 注入
再次查看上面的示例。代码的最初目的是创建一个 SQL 语句来选择一个用户,并使用给定的用户 ID。
如果没有阻止用户输入“错误”输入,用户可以输入一些“智能”输入,例如
UserId
然后,SQL 语句将如下所示
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
上面的 SQL 是有效的,将从“Users”表返回所有行,因为 OR 1=1始终为 TRUE。
上面的示例看起来危险吗?如果“Users”表包含姓名和密码怎么办?
上面的 SQL 语句与下面语句几乎相同
SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1;
黑客只需在输入字段中插入 105 OR 1=1,就可以访问数据库中的所有用户名和密码。
基于 ""="" 始终为真的 SQL 注入
以下是一个网站上用户登录的示例
用户名
密码
示例
uName = getRequestString("username");
uPass = getRequestString("userpassword");
sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass + '"'
结果
SELECT * FROM Users WHERE Name ="John Doe" AND Pass ="myPass"
黑客只需在用户名或密码文本框中插入 " OR ""="",就可以访问数据库中的用户名和密码。
用户名
密码
服务器上的代码将创建一个有效的 SQL 语句,如下所示
结果
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
上面的 SQL 是有效的,将从“Users”表返回所有行,因为OR ""=""始终为 TRUE。
基于批处理 SQL 语句的 SQL 注入
大多数数据库支持批处理 SQL 语句。
一批 SQL 语句是两个或多个 SQL 语句的集合,用分号隔开。
下面的 SQL 语句将从“Users”表返回所有行,然后删除“Suppliers”表。
示例
SELECT * FROM Users; DROP TABLE Suppliers
请看下面的示例
示例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
以及以下输入
用户 ID
有效的 SQL 语句将如下所示
结果
SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;
使用 SQL 参数进行保护
为了保护网站免受 SQL 注入,您可以使用 SQL 参数。
SQL 参数是在执行时以受控方式添加到 SQL 查询中的值。
ASP.NET Razor 示例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);
请注意,参数在 SQL 语句中由 @ 标记表示。
SQL 引擎检查每个参数,以确保它与其列正确匹配,并按字面意思处理,而不是作为要执行的 SQL 的一部分。
另一个示例
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);
示例
以下示例展示了如何在一些常见的 Web 语言中构建参数化查询。
ASP.NET 中的 SELECT 语句
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserId);
command.ExecuteReader();
ASP.NET 中的 INSERT INTO 语句
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();
PHP 中的 INSERT INTO 语句
$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();