什么是SQL注入?[复制]

What is SQL injection? [duplicate]

提问人: 提问时间:3/2/2009 最后编辑:Bhargav Rao 更新时间:8/19/2019 访问量:44270

问:

有人可以解释SQL注入吗?它如何导致漏洞?SQL注入点到底在哪里?

SQL SQL注入 安全性

评论

0赞 mezoid 3/2/2009
@David 有点含糊不清......但比苏布最初问的时候要清楚得多。:-)
1赞 jcolebrand 5/1/2010
@Chris Thornton - 你怎么会不使用参数化查询?这样就不需要了......
3赞 outis 5/1/2010
参见:unixwiz.net/techtips/sql-injection.htmlsecuriteam.com/securityreviews/5DP0N1P76E.htmlowasp.org/index.php/SQL_injectionen.wikipedia.org/wiki/SQL_injectionmsdn.microsoft.com/en-us/library/ms161953.aspx、php.net/manual/en/security.database.sql-injection.php
2赞 Neil N 3/2/2009
阅读参数化查询
1赞 DevSolar 3/2/2009
这是 SQL 注入。

答:

5赞 Chad Birch 3/2/2009 #1

我发现这篇论文是一本关于SQL注入技术的非常好的读物(链接是PDF):SQL Server应用程序中的高级SQL注入

尽管标题上写着“高级”,但即使您对 SQL 注入没有太多了解,它也非常可读。

评论

0赞 Chad Birch 4/9/2011
@johnmortal:谢谢,我用一个有效的链接替换了链接。我的头像是《女神异闻录3》中的主角。
2赞 acrosman 3/2/2009 #2

要获得一些一般的背景知识,请查看维基百科上关于SQL注入的文章

简而言之,SQL注入攻击会使您容易受到数据库数据盗窃和破坏的所有影响。可以对系统执行的操作的确切细节取决于系统本身的详细信息。

每当您将用户的输入传递到数据库时,您都有一个潜在的注入点。Web 应用程序通常在这方面有所欠缺,因为新程序员通常不了解处理用户输入的风险,并且 Web 应用程序受到您从未想过会找到您的程序的非常聪明的人的攻击。

0赞 thomasrutter 3/2/2009 #3

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

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

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

29赞 Jim OHalloran 3/2/2009 #4

当应用程序的用户能够影响数据库查询的含义时,就会发生 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 Inection 还可用于执行 UPDATE、DELETE 或 DROP 查询,并真正损坏数据库。

可以通过使用参数化查询或应用语言/工具包的转义函数(例如 PHP 中的 mysql_real_escape_string()来防止 SQL 注入。

一旦你理解了SQL注入,你就会明白这部漫画背后的笑话。

93赞 Bill Karwin 3/2/2009 #5

有人可以解释SQL注入吗?

当您将某些内容插值到 SQL 查询字符串中时,就会发生 SQL 注入,并且结果会以您不希望的方式修改查询的语法。

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

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

它如何导致漏洞?

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

PHP 示例:

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

现在假设攻击者将 POST 请求参数设置为 “” 和 “”,从而导致以下 SQL:password=xyzzyid=account_id

UPDATE Accounts SET PASSWORD = 'xyzzy' WHERE account_id = account_id

尽管我期望是整数,但攻击者选择了一个字符串作为列的名称。当然,现在一行的条件都是真,所以攻击者只是为每个帐户设置了密码。现在,攻击者可以登录任何人的帐户,包括特权用户。$id

SQL注入点到底在哪里?

注入的不是 SQL,而是插入(“注入”)到 SQL 字符串中的内容,从而产生与我预期的不同类型的查询。我信任动态内容而没有验证它,并盲目地执行了生成的 SQL 查询。这就是麻烦开始的地方。

SQL 注入是应用程序代码中的错误,通常不在数据库或数据库访问库或框架中。

大多数情况下,使用查询参数可以避免 SQL 注入。有关示例,请参阅如何防止 PHP 中的 SQL 注入?

评论

0赞 pero 4/16/2011
sql参数呢?IMO 它应该是您免受 sql 注入的第一道防线!如果可能,请避免将内容注入 sql 字符串。内容应放入参数中。这样,DB 就知道内容不是 sql 的一部分,因此您会自动安全。
1赞 Bill Karwin 4/20/2011
@Petar Repac:是的,查询参数很好,我建议使用它们。但参数只能替换单个值。不能将参数用于表或列标识符、SQL 关键字、IN() 谓词中的值列表或其他 SQL 表达式或语法。参数很有用,但对于其他情况,您需要其他技术。
7赞 John Weldon 5/1/2010 #6

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

我坚持的 #1 建议是使用参数化存储过程,而不是在代码中构建原始 SQL。

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

1赞 SDReyes 5/1/2010 #7

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

总结

  • 加密敏感数据。
  • 使用具有最低权限的帐户访问数据库 必要。
  • 使用具有最低权限的帐户安装数据库 必要。
  • 确保数据有效。
  • 进行代码审查以检查二阶的可能性 攻击。
  • 使用参数化查询。
  • 使用存储过程。
  • 重新验证存储过程中的数据。
  • 确保错误消息不会泄露任何有关内部的信息 应用程序的体系结构或 数据库。

评论

0赞 L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 5/1/2010
LOL二阶攻击
0赞 SDReyes 5/1/2010
哈哈哈哈,是的,我知道。但这是一组应该考虑的变量;)
16赞 Bill Karwin 5/1/2010 #8

这个问题在 StackOverflow 上已经回答过很多次了,但这是一个每个人都要知道的重要话题,所以我不打算投票来结束这个问题。

以下是我过去关于这个主题的一些答案的链接:

我还在本月的MySQL大会上做了一个演讲,我的幻灯片已经上线了:

14赞 Sebastian Paaske Tørholm 5/1/2010 #9

SQL注入是指本应是数据的东西不情愿地被视为SQL代码。

例如,如果你要这样做

mysql_query("SELECT * FROM posts WHERE postid=$postid");

通常它会为您提供具有给定 id 的帖子,但假设将其设置为字符串;突然之间,您发送的实际查询是$postid10; DROP TABLE posts --

mysql_query("SELECT * FROM posts WHERE postid=10; DROP TABLE posts --");

这是一个相当大的问题,因为由于恶意用户,您将丢失整个帖子表 - 哦,亲爱的。

防止这种情况的最简单方法是使用准备好的语句,例如通过 PDOMySQLi

PDO中的等效示例将是

$statement = $db->prepare('SELECT * FROM posts WHERE postid = :postid');
$statement->bindValue(':postid', $postid);
$statement->execute();

这样做可以确保数据库系统知道$postid将被视为数据而不是代码,因此将得到适当的处理。