这个SQL注入如何工作? 需要说明
我正在学习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上搜索过,但我没有得到它背后的概念。 有帮助吗?
最简单的解释我可以给出SQL注入的内容:
这可能会使SQL查询如下所示:
SELECT * FROM Order WHERE name = 'Dan' AND pay_type = 'po'
现在一个不错的用户会像上面那样提供Dan这个名字。
但是一个邪恶的用户(让我们称他为Bobby),将提供名称: 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)
现在如果邪恶的Bobby带着他的名字:“Bobby Tables”; DROP DATABASE主; –
if会参数化(和转义引用)查询,如:
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 name where name = [some parameter]”,然后在它之后添加参数。)所以你得到的将是一个非常奇怪的平等,其中name =“); drop table blah ;” 除非你的数据中有一些奇怪的名字,否则这当然不会奏效。
注意,注入必须实际正确地结束命令并启动一个新命令 – 否则它只会导致错误。
这似乎是一个小小的狡辩,但如果你没有做到这一点,它会产生巨大的影响。 纪律极为重要。 如果你忘记了这一点, 你会度过糟糕的一天,因为一旦发现漏洞,人们可以做些非常讨厌的事情 。
每天都有另一个例子,说明一开始就没有认真对待一个小小的错误会导致严重的问题。 今天的例子:由于单个参数没有被转义, 4chan被黑了。 这就是全部。 一个错误。
尽可能使用SQL占位符作为值。 不要走快捷方式。 风险太高了。
ActiveRecord有许多方法来编写不涉及直接操作查询的查询:
Order.where(name: 'name', pay_type: 'po')
尽可能使用这些。 如果您遇到限制,请尽可能安全地进行:
Order.where([ 'name LIKE ?', "%#{name}" ])
您还可以更直接地使用转义function:
Order.sanitize(name)
如果您必须在查询中引入一些任意文本,请确保它已经过彻底validation。 始终列出一个非常狭窄的已接受参数列表。 不要错误地添加一些排除规则,这样就会忘记忘记规则。 它的音质要比太宽松要严格得多。
使用Rails,你的基础非常好。 不要搞砸了。 避免大量混乱的一种方法是使用单引号字符串,因此插值是禁止的:
Order.where('name="#{name}"') # Won't work, isn't interpolated.
如果养成这种习惯,那么你应该非常犹豫是否要切换到内插字符串。
如果您掌握了所有这些,那么您需要记住,在HTML空间中需要了解完全相同的模式,您需要了解需要相同级别规则的XSS和HTML注入问题。 在现代Rails中,所有用户数据都在视图中自动进行HTML转义,但这并不总是有助于嵌入式JavaScript。 每当您有疑问时,询问您所做的事情是否安全无法确定。
关于这方面的内容很多,所以我不打算讨论它,但是为了回答你的问题,黑客可以发出一个GO然后删除数据库OR; DROP DATABASE等。作为Heartbleed已经告诉我们,如果你不知道它会更具破坏性,他们可以做一些像“99;从主人那里选择*”来获取敏感信息。 为了保护,您最常被引导使用存储过程WITH参数来让DBMSvalidation并且永远不会将事物串在一起作为动态SQL,除非您真的必须这样做。 它很危险,性能几乎总是受到负面影响。