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