这个 SQL 注入是如何工作的?需要解释

Posted

技术标签:

【中文标题】这个 SQL 注入是如何工作的?需要解释【英文标题】:How this SQL injection works? Explanation needed 【发布时间】:2014-06-25 02:27:21 【问题描述】:

我正在学习 RoR/数据库,这个话题让我特别困惑。在 Agile Development with Rails 4 一书中,他们给出了一个示例,用于查找名称为 Dave 的条目的所有订单列表:

pos = Order.where("name = 'Dave' and pay_type = 'po")

这本书接着说,你永远不会想做这样的事情:

name = params[:name]
pos = Order.where("name = '#name'and pay_type = 'po'")

您应该这样做:

name = params[:name]
pos = Order.where(["name = ? and pay_type = 'po'",name])

我明白,SQL 注入是一个概念,但有一些细节让我感到困惑。对于初学者来说,SQL 注入作为一种语法究竟是如何工作的。

我知道危险在于,如果您像第一个示例那样插入外部表单参数,那么有人可能会删除表/数据库,但如何?

假设你有这个:

name = params[:name] #DROP DATABASE database_name
pos = Order.where("name = '#DROP DATABASE database_name'and pay_type = 'po'")

这就是 SQL 注入的工作原理吗? SQL是一种语法,数据库中应该没有“name = DROP DATABASE database_name”的字段,这不会返回错误而不是删除数据库吗?

另外,问号版本如何防止这种情况发生。同样,假设您有这种情况。

name = params[:name] #DROP DATABASE database_name
pos = Order.where(["name = ? and pay_type = 'po'", DROP DATABASE database_name])

这不会用 DROP DATABASE database_name 语法替换问号,那么我们会不会遇到与第一个示例中相同的问题?这究竟如何保护应用程序免受 SQL 攻击?我在http://hub.tutsplus.com/ 上搜索了一些教程并在谷歌上搜索,但我不明白它背后的概念。有什么帮助吗?

【问题讨论】:

这似乎相关:xkcd.com/327 感谢 Ellesedil 的快速回复,我以前确实见过这个,但我不明白它是如何工作的。正如我在上面的问题中提到的,问号会被变量名替换,就像第一个没有它的例子一样,所以基本上你会插入相同的删除表语法。还是谢谢 这并不完全是重复的,但大部分可以由the seminal php injection question回答。 【参考方案1】:

我能给出的关于什么是 SQL 注入的最简单解释:

这可能会产生如下 SQL 查询:

SELECT * FROM Order WHERE name = 'Dan' AND pay_type = 'po'

现在一个好的用户会像上面一样提供名称 Dan。

但是一个邪恶的用户(我们叫他 Bobby)会提供这个名字: Bobby Tables'; DROP DATABASE master; --

这会创建如下查询:

SELECT * FROM Order WHERE name = 'Bobby Tables'; DROP DATABASE master; --' AND pay_type = 'po'

它有效地执行了两个查询:

SELECT *
FROM Order
WHERE name = 'Bobby Tables';

DROP DATABASE master;

现在数据库已经消失了。当他们从数据库中提取私人信息(如用户名/密码或信用卡信息)时,会造成更严重的损害


至于为什么问号现在能神奇地保护你:

在 RoR 中使用问号,利用了一种称为参数化的模式。当你参数化一个 SQL 查询时,你编写它的方式是防止任何人输入一个成功的 SQL 注入。在任何使用问号的地方,它都被一个参数代替。然后通过转义任何引号将该参数安全地设置为查询顶部的值。

如果您现在将姓名 Dan 提供给:

Order.where(["name = ? and pay_type = 'po'", params[:name])

查询看起来像:(RoR 内部参数化可能略有不同,但效果相同)

DECLARE @p0 nvarchar(4000) = N'po',
        @p1 nvarchar(4000) = N'Dan';

SELECT [t0].[ID], [t0].[name], [t0].[pay_type]
FROM Order AS [t0]
WHERE ([t0].[name] = @p1) AND ([t0].[pay_type] = @p1) 

现在,如果邪恶的鲍比带着他的名字出现: “鲍比桌”;删除数据库主; --

如果将参数化(并转义引号)查询,例如:

DECLARE @p0 nvarchar(4000) = N'po',
        @p1 nvarchar(4000) = N'Bobby Tables''; DROP DATABASE master; --';

SELECT [t0].[ID], [t0].[name], [t0].[pay_type]
FROM Order AS [t0]
WHERE ([t0].[name] = @p1) AND ([t0].[pay_type] = @p1) 

现在这是一个非常安全的查询

希望能帮助你理解

【讨论】:

【参考方案2】:

这与代码解释器的工作方式有关。

在第一个示例中,参数只是作为文本插入,然后处理整个命令。因此,问题。

在第二个示例中,首先解释命令,然后插入参数。 (IE,它解释“do statement where name=[some parameter]”,然后在它之后添加参数。)所以你得到的只是一个非常奇怪的等式 where name = "); drop table blah ;"除非您的数据中有一些奇怪的名称,否则这当然是行不通的。

注意,注入必须真正正确地结束您的命令并启动一个新命令 - 否则只会导致错误。

【讨论】:

【参考方案3】:

这似乎是一个小问题,但如果你没有做到这一点,它会产生巨大的影响。纪律是极其重要的。如果您忘记了这一点,you will have a bad day 因为某些very nasty things 人们一旦发现漏洞就可以这样做。

每天都有另一个例子说明,从一开始就没有认真对待事情所造成的微小错误如何导致严重问题。今天的例子:4chan gets hacked 由于单个参数没有被转义。这就是它所需要的。一个错误。

尽可能使用 SQL 占位符来表示值。 不要走捷径。风险太高了。

ActiveRecord 有许多不涉及直接操作查询的组合查询方法:

Order.where(name: 'name', pay_type: 'po')

尽可能使用这些。如果您遇到限制,请尽可能安全地进行:

Order.where([ 'name LIKE ?', "%#name" ])

你也可以更直接地使用转义功能:

Order.sanitize(name)

如果您必须在查询中引入一些任意文本,请确保其经过全面验证。始终列出非常窄的可接受参数列表。不要错误地添加一些排除规则,这会留下您忘记的可能性。语气太严格总比太松懈好。

有了 Rails,您就有了很好的基础。不要搞砸了。避免这种混乱的一种方法是使用单引号字符串,因此插值是禁止的:

Order.where('name="#name"') # Won't work, isn't interpolated.

如果你养成了习惯,那应该会让你非常犹豫是否要切换到插值字符串。

如果您掌握了这一切,您需要记住,完全html 空间中会出现相同的模式,您需要注意 XSS 和 HTML 注入问题需要同样的纪律。在现代 Rails 中,所有用户数据都会在视图中自动进行 HTML 转义,但这并不总是有助于嵌入 javascript。每当您有疑问时,请询问您所做的事情是否安全。

【讨论】:

【参考方案4】:

这方面已经写了很多,所以我不打算进入它,但为了回答你的问题,黑客可以根据数据库发出 GO 然后删除数据库或 ;DROP DATABASE 等。正如 Heartbleed 告诉我们的那样,如果您不知道,他们可能会执行“99;select * from master”之类的操作来获取敏感信息,从而造成更大的破坏。为了保护,您通常会被引导使用带有参数的存储过程来让 DBMS 进行验证,并且除非您真的必须这样做,否则永远不要将事物作为动态 SQL 串在一起。这很危险,而且性能几乎总是受到负面影响。

【讨论】:

以上是关于这个 SQL 注入是如何工作的?需要解释的主要内容,如果未能解决你的问题,请参考以下文章

"Bobby Tables" XKCD 漫画中的 SQL 注入是如何工作的?

我不明白注入依赖是如何工作的。有没有人可以清楚地解释我

SQL 注入在概念上是如何工作的? (简要)[重复]

从哪里获得有关二阶 SQL 注入的资源和演示?

如何防止sql注入oracle apex

绕过安全狗进行sql注入(MySQL)