什么是SQL注入?

107

有人能解释一下什么是SQL注入吗?它是如何导致安全漏洞的?SQL注入发生在哪个具体点?


2
阅读有关参数化查询的内容。 - Neil N
@mezoid:没错,我的评论实际上是指原始版本。现在好多了;-) - David Z
1
这是SQL注入。 - DevSolar
1
@Chris Thornton - 你们为什么不使用参数化查询?这将消除需要... - jcolebrand
3
另请参阅:http://unixwiz.net/techtips/sql-injection.html,http://www.securiteam.com/securityreviews/5DP0N1P76E.html,http://www.owasp.org/index.php/SQL_injection,http://en.wikipedia.org/wiki/SQL_injection,http://msdn.microsoft.com/en-us/library/ms161953.aspx,http://www.php.net/manual/en/security.database.sql-injection.php - outis
显示剩余7条评论
9个回答

93

有人能解释一下什么是SQL注入吗?

当你把一些内容插入到 SQL 查询字符串中时,如果结果修改了你原本不想要的查询语法,就会发生 SQL 注入。

这并不一定是恶意的,可能是意外的。但是意外的 SQL 注入更可能导致错误而不是漏洞。

有害内容不一定来自用户,它可以来自应用程序从任何来源获取的内容,甚至在代码中自动生成的内容。

它如何导致漏洞?

它会导致漏洞,因为攻击者可以向应用程序发送值,他们知道这些值将被插入到 SQL 字符串中。通过非常聪明的方式,他们可以操纵查询结果,读取数据或甚至更改他们不应该被允许更改的数据。

PHP 中的示例:

$password = $_POST['password'];
$id = $_POST['id'];
$sql = "UPDATE Accounts SET PASSWORD = '$password' WHERE account_id = $id";

假设攻击者将POST请求参数设置为"password=xyzzy"和"id=account_id", 导致以下SQL查询语句:

UPDATE Accounts SET PASSWORD = 'xyzzy' WHERE account_id = account_id
尽管我期望$id是一个整数,但攻击者选择了一个作为列名的字符串。当然,现在条件在每一行上都成立,因此攻击者只是设置了每个账户的密码。现在攻击者可以登录任何人的帐户,包括特权用户。 SQL注入的确切点在哪里? 不是SQL被注入了,而是内容被插入到SQL字符串中(“注入”),导致查询的类型与我的意图不同。我没有验证动态内容,就盲目地执行了结果的SQL查询,这就是问题的起源。
SQL注入是应用程序代码的错误,通常不是数据库或数据库访问库框架的错误。
大多数情况下,可以通过使用查询参数来避免SQL注入。请参见如何在PHP中防止SQL注入?以获取示例。

SQL参数怎么样?在我看来,这应该是防止SQL注入的第一道防线!如果可能的话,请避免将注入内容放入SQL字符串中。内容应该放在参数中。这样数据库就知道该内容不是SQL的一部分,因此您自动就是安全的。 - pero
1
@Petar Repac:是的,查询参数很好,我建议使用它们。但是一个参数只能替代单个值。您不能将参数用于表或列标识符、SQL关键字、IN()谓词中的值列表或其他SQL表达式或语法。参数很有用,但对于其他情况,您需要其他技术。 - Bill Karwin

29

SQL注入是指应用程序的用户能够影响数据库查询的含义。这通常发生在将来自用户输入的任意字符串连接起来创建SQL并将其提供给数据库时。例如,假设我们有以下代码(使用PHP编写,但对于任何语言都是适用的),该代码可能用于处理用户登录。

$sql = "SELECT  FROM users WHERE username='".$_GET['username']."' AND password='".$_GET['password']."'";

当用户输入类似于

时,就会造成损害。
administrator'; --

...用于用户名。如果没有适当的编码,查询将变成:

SELECT * FROM users WHERE username='administrator'; -- AND password=''

问题在于用户名中的'会关闭用户名字段,然后--开始一个SQL注释,导致数据库服务器忽略字符串的其余部分。结果是用户现在可以作为管理员登录而无需知道密码。 SQL注入也可以用于执行UPDATE、DELETE或DROP查询并真正破坏数据库。使用参数化查询或应用语言/工具包的转义函数(如PHP中的mysql_real_escape_string())可以防止SQL注入。一旦你理解了SQL注入,你就会明白这个漫画的笑话了。

16

14
SQL注入是指将本应作为数据处理的内容被错误地视为SQL代码。
例如,如果你执行以下操作:
mysql_query("SELECT * FROM posts WHERE postid=$postid");

通常情况下,它会根据给定的id获取帖子,但假设$postid被设置为字符串10; DROP TABLE posts --;突然之间,你发送的实际查询变成了:
mysql_query("SELECT * FROM posts WHERE postid=10; DROP TABLE posts --");

这是一个相当大的问题,因为你可能会因为一个恶意用户而丢失整个帖子表 - 哎呀。
最简单的方法是使用预处理语句,例如通过PDO或MySQLi。
PDO中的等效示例如下:
$statement = $db->prepare('SELECT * FROM posts WHERE postid = :postid');
$statement->bindValue(':postid', $postid);
$statement->execute();

这样做可以确保数据库系统知道$postid应被视为数据而非代码,并且会相应地进行处理。

7

SQL注入是指恶意用户将SQL代码输入到输入字段中,以尝试在您的服务器上运行SQL。

我所坚持的第一条建议是使用参数化存储过程而非在代码中构建原始SQL。

存储过程参数不会被执行,在大多数情况下是安全的。


5
我找到一篇关于SQL注入技术的非常好的文章(PDF链接):Advanced SQL Injection In SQL Server Applications。尽管标题写着“高级”,但即使你对SQL注入没有太多知识,它也很易读。请见链接:Advanced SQL Injection In SQL Server Applications

@johnmortal:谢谢,我已经用一个有效的链接替换了那个链接。我的头像是来自于女神异闻录3的主角。 - Chad Birch

2
要了解一些基本背景,请查看SQL注入的维基百科文章
简而言之,SQL注入攻击可能会使您容易受到各种数据库数据盗窃和破坏的威胁。具体可以对系统进行什么样的操作取决于系统本身的详细信息。
每当您将用户输入传递给数据库时,都存在潜在的注入点。Web应用程序在这方面通常缺乏保护,因为新手程序员经常不了解处理用户输入的风险,而且Web应用程序会受到非常聪明的黑客攻击,这是您从未想过会找到您的程序的人。

1

你会喜欢来自代码项目的this文章;)

摘要

  • 加密敏感数据。
  • 使用最少权限的帐户访问数据库。
  • 使用最少权限的帐户安装数据库。
  • 确保数据有效。
  • 进行代码审查,以检查是否存在二次攻击的可能性。
  • 使用参数化查询。
  • 使用存储过程。
  • 在存储过程中重新验证数据。
  • 确保错误消息不透露应用程序或数据库的内部架构。

LOL二级攻击 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
哈哈哈哈,是的我知道。但这是一组应该考虑的变量;) - SDReyes

0

SQL注入的发生点是您的应用程序从用户接受输入的任何点。

无论这是否成为您的Web应用程序的危险漏洞,取决于此输入是否稍后作为SQL查询的一部分使用,而没有正确检查其类型并在必要时进行转义。

如果没有适当的转义,用户“注入”的某些SQL代码可能会被SQL引擎执行为SQL代码,而不是简单的字符串或值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接