这个SQL注入如何工作?需要说明

时间:2014-05-07 21:54:01

标签: sql ruby-on-rails ruby sql-injection

我正在学习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/上搜索了一些教程并在Google上搜索过,但我并没有得到它背后的概念。有什么帮助吗?

4 个答案:

答案 0 :(得分:5)

我可以给出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) 

现在如果邪恶的鲍比带着他的名字: “Bobby Tables”; DROP DATABASE主; -

如果将参数化(和转义引用)查询,如:

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) 

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

希望能帮助您理解

答案 1 :(得分:3)

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

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

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

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

答案 2 :(得分:2)

这可能看起来像是一个小小的狡辩,但如果你没有做到这一点,它会产生巨大的影响。纪律极为重要。如果您忘记了这一点,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.

如果养成习惯,那么你应该非常犹豫地转换为插值字符串。

如果你掌握了所有这些,你需要记住完全相同的模式在你需要了解XSS和HTML注入的HTML空间中发挥作用需要相同程度纪律的问题。在现代Rails中,所有用户数据都在视图中自动进行HTML转义,但这并不总是有助于嵌入式JavaScript。如果您有任何疑问,请询问您所做的事情是否安全无法确定。

答案 3 :(得分:0)

关于这方面已有很多内容,所以我不打算进入,但为了回答你的问题,黑客,根据数据库,可以发出GO然后删除数据库OR; DROP DATABASE等。正如Heartbleed告诉我们的那样,如果你不知道并且他们可以做类似" 99;从主人那里选择*"那就更具破坏性了。获取敏感信息。为了保护,您最常被引导使用存储过程WITH参数来让DBMS验证并且永远不会将事物串在一起作为动态SQL,除非您真的必须这样做。它很危险,性能几乎总是受到负面影响。