这个 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 注入是如何工作的?需要解释的主要内容,如果未能解决你的问题,请参考以下文章