轻松上手,快乐学习!

SQL 注入


SQL 注入

SQL注入是一种代码注入技术,可能会破坏您的数据库。

SQL注入是最常见的Web黑客技术之一。

SQL注入是通过网页输入在SQL语句中放置恶意代码。


网页中的SQL

当您向用户询问输入时,通常会发生SQL注入,例如用户名,提供不是用户名而是一条SQL语句,您将无意中在数据库上运行该语句。

请查看以下示例,该示例通过向选择字符串添加变量(txtUserId)来创建SELECT语句。该变量是从用户输入(getRequestString)获取的:

实例

txtUserId = getRequestString("UserId");
txtSQL = "SELECT *FROM Users WHERE UserId = " + txtUserId;

本章的其余部分描述了在SQL语句中使用用户输入的潜在危险。


SQL注入基于1 = 1始终为True

再看一下上面的例子。代码的最初目的是创建一个SQL语句来选择具有给定用户ID的用户。

如果没有什么可以防止用户输入“错误”输入,用户可以输入一些“智能”输入,如下所示:

用户身份: 

然后,SQL语句将如下所示:

SELECT * FROM Users WHERE UserId = 105 OR 1=1;

上面的SQL是有效的,将返回“Users”表中的所有行,因为OR 1 = 1始终为TRUE。

上面的例子看起来很危险吗?如果“用户”表包含名称和密码怎么办?

上面的SQL语句与此大致相同:

SELECT UserId, Name, PasswordFROM Users WHERE UserId = 105 or 1=1;

黑客可以通过在输入字段中插入105 OR 1 = 1来访问数据库中的所有用户名和密码。


SQL注入基于""=""的始终为True

以下是用户在网站上登录的示例:

用户名:

密码:

实例

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;

以下输入:

用户身份: 

有效的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中选择语句:

txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserID);
command.ExecuteReader();

在ASP.NET中插入声明:

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中插入声明:

$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();