最新的Web开发教程
 

SQL注射


SQL注入可以摧毁你的数据库。


SQL在网页

在前面的章节中,你已经学会了检索(和更新)数据库中的数据,使用SQL。

当SQL是用于在网页上显示的数据,是很常见的,让网络用户输入自己的搜索值。

由于SQL语句是纯文本,很容易,用少许一段计算机代码,来动态改变SQL语句来提供选择数据的用户:

服务器代码

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

上面的例子,加入一个变量(txtUserId)将选择字符串创建一个select语句。 变量是来自用户的输入(请求)至页面中取出。

本章的其余部分将介绍在SQL语句中使用用户输入的潜在危险。


SQL注入

SQL注入是一个技术,其中恶意用户可以SQL命令注入SQL语句,通过网页输入。

注入SQL命令可以改变SQL语句和妥协的Web应用程序的安全性。


基于1 = 1 SQL注入始终是真实的

看看上面的例子,一个更多的时间。

比方说,代码的最初目的是创建一个SQL语句来选择与给定用户ID的用户。

如果没有什么可以阻止用户进入"wrong"输入,用户可以输入一些"smart"输入是这样的:

用户名:

服务器结果

SELECT * FROM Users WHERE UserId = 105 or 1=1

上述的SQL是有效的。 它将从表中的用户返回所有行,因为1 = 1始终为true。

请问上面的例子似乎很危险吗? 如果用户表中包含名和密码?

上述SQL语句是大致相同的,因为这:

SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1

智能黑客可能通过简单地插入105或1 = 1到输入框获得所有数据库中的用户名和密码。


SQL注入基于""=""始终是真实的

这是一个常见的结构,用于验证用户登录到一个网站:

用户名:

密码:

服务器代码

uName = getRequestString("UserName");
uPass = getRequestString("UserPass");

sql = "SELECT * FROM Users WHERE Name ='" + uName + "' AND Pass ='" + uPass + "'"

一个聪明的黑客可能通过简单地插入“或可以访问用户名和密码在数据库""="到用户名或密码文本框。

在服务器上的代码将创建这样一个有效的SQL语句:

结果

SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""

结果的SQL是有效的。 它将从表中的用户返回所有行,因为WHERE“”=“”始终是真实的。


基于成批的SQL语句的SQL注入

大多数数据库支持批处理SQL语句,用分号隔开。

SELECT * FROM Users; DROP TABLE Suppliers

在上面的SQL将返回用户表中的所有行,然后删除该表称为供应商。

如果我们有以下服务器的代码:

服务器代码

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

而下面的输入:

用户名:

在服务器上的代码将创建这样一个有效的SQL语句:

结果

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers

为保护参数

一些Web开发人员使用一个"blacklist"字或字符的搜索中输入的SQL语句,防止SQL注入攻击。

这不是一个很好的主意。 许多这样的话(如删除或下降)和字符(比如分号和引号),在共同的语言使用,并且应当在许多类型的输入被允许。

(事实上​​,它应该是完全合法的输入数据库字段的SQL语句。)

以防止SQL注入攻击一个网站的唯一行之有效的方法,是使用SQL参数。

SQL参数是添加到SQL查询在执行时,以受控的方式值。

ASP.NET剃刀例

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

你刚才教训,避免SQL注入。 一个顶级网站的漏洞。


例子

下面的例子演示了如何在一些常见的网络语言构建参数化查询。

SELECT语句ASP.NET:

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

INSERT INTO声明在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();

INSERT INTO声明在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();