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

我正在学习RoR /数据库,这个话题让我特别困惑。 在“使用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上搜索,但我没有看到它背后的概念。 任何帮助?


我可以给出什么SQL注入最简单的解释是:

这可能会使SQL查询如下所示:

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

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

但是一个邪恶的用户(让我们称他为鲍比),将会提供这个名字: Bobby Tables'; DROP DATABASE master; -- 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) 

现在,如果邪恶的鲍比带着他的名字:鲍比桌子, DROP DATABASE master; -

如果将参数化(和转义引号)如下查询:

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) 

这现在是一个完全安全的查询

希望能帮助你理解


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

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

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

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


这可能看起来像一个小问题,但如果你没有做到这一点,它会产生巨大的影响。 纪律非常重要。 如果你忘记了这一点,那么你将会面临糟糕的一天,因为一旦人们发现漏洞,人们可以做一些非常令人讨厌的事情。

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

尽可能为值使用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并不总是有帮助。 每当你有问题时,询问你所做的事情是否安全或不确定。

链接地址: http://www.djcxy.com/p/16769.html

上一篇: How this SQL injection works? Explanation needed

下一篇: How can prepared statements protect from SQL injection attacks?