防御“WAITFOR DELAY”sql 注入攻击?

Posted

技术标签:

【中文标题】防御“WAITFOR DELAY”sql 注入攻击?【英文标题】:Defending against a 'WAITFOR DELAY' sql injection attack? 【发布时间】:2011-01-02 16:34:23 【问题描述】:

问题

我们需要在我们的 java 应用程序中防御 'WAITFOR DELAY' sql 注入攻击。

背景

[这很长。跳到“解决方案?”如果您赶时间,请参阅下面的部分]

我们的应用程序在访问数据库时主要使用准备好的语句和可调用的语句(存储过程)。

在一些地方,我们动态地构建和执行查询以进行选择。在这个范例中,我们使用标准对象来根据用户输入标准构建查询。例如,如果用户为 first_name 和 last_name 指定了值,则查询结果总是如下所示:

SELECT first_name,last_name FROM MEMBER WHERE first_name ='joe' AND last_name='frazier'

(在此示例中,用户将指定“joe”和“frazier”作为他/她的输入值。如果用户有更多或更少的条件,我们将有更长或更短的查询。我们发现这种方法更容易比使用准备好的语句并且比存储过程更快/更高效)。

攻击

漏洞审核报告了 sql 注入失败。攻击者为 'last_name' 参数注入了值 'frazier WAITFOR DELAY '00:00:20' ,产生了这个 sql:

   SELECT first_name,last_name FROM MEMBER WHERE first_name ='joe' AND last_name='frazier' WAITFOR DELAY '00:00:20'

结果:查询执行成功,但执行需要 20 秒。攻击者可以将您的所有数据库连接绑定在数据库池中,并有效地关闭您的站点。

关于这种“WAITFOR DELAY”攻击的一些观察

我曾认为,因为我们使用了 Statement executeQuery(String),所以我们可以避免 sql 注入。 executeQuery(String) 不会执行 DML 或 DDL(删除或删除)。并且 executeQuery(String) 阻塞分号,因此“Bobby Tables”范式将失败(即用户输入“frazier; DROP TABLE member”作为参数。参见http://xkcd.com/327/)

“WAITFOR”攻击在一个重要方面有所不同:WAITFOR 修改了现有的“SELECT”命令,而不是单独的命令。

该攻击仅适用于结果查询中的“最后一个参数”。即 'WAITFOR' 必须出现在 sql 语句的最后

解决方案、廉价黑客,还是两者兼而有之?

最明显的解决方案是将“AND 1=1”简单地添加到 where 子句中。

生成的 sql 立即失败并挫败了攻击者:

   SELECT first_name,last_name FROM MEMBER WHERE first_name ='joe' AND last_name='frazier' WAITFOR DELAY '00:00:20' AND 1=1

问题

这是 WAITFOR 攻击的可行解决方案吗? 它是否可以防御其他类似的漏洞? 我认为最好的选择是使用准备好的语句。工作更多,但不那么脆弱。

【问题讨论】:

不幸的是,它挫败的唯一人就是你自己。如果你坚持,而不是延迟,“OR 1 = 1”,你最终可能会允许任何人和每个人登录。不要试图欺骗自己,认为你可以设法胜过所有想要尝试的人破坏您的网站。你是一个人,如果你的网站很受欢迎,他们很多。如果不是,那么你做什么(如果有的话)可能并不重要。 规则 #1:不要合成和执行来自不受信任来源的代码... 【参考方案1】:

处理 SQL 注入的正确方法是使用参数化查询。其他一切都只是随风而逝。它可能会起作用一次,甚至两次,但最终你会被那种“你搞砸了,糟糕透顶!”的温暖感觉击中。

无论您做什么,除了参数化查询,都将是次优的,您需要确保您的解决方案没有其他需要修补的漏洞。

另一方面,参数化查询开箱即用,可以防止所有这些攻击。

【讨论】:

好点,我想我应该更具体一些 - 如果你传递一个大的连接字符串而不是一个带有参数占位符的准备好的语句,它对你没有任何好处! 这就是为什么我说“参数化查询”,而不是“准备好的查询”。 “处理SQL注入的正确方法是使用参数化查询。其他一切都只是在风中撒尿”谢谢你说实话!这实际上是几乎所有安全编程问题的答案。 不错!很好的解决方案,但我最喜欢“在风中撒尿”:))))))【参考方案2】:

SQL 注入就是 SQL 注入 - WAITFOR DELAY 没有什么特别之处。

在当今时代,绝对没有理由不使用准备好的语句进行如此简单的查询。

(编辑:好吧,不是“绝对”——但几乎从来没有借口)

【讨论】:

查看代码,其中几个“finder”DAO 方法会生成“IN 子句”(即“WHERE STATUS in (1,2,3)”)。没有任何借口,但准备好的陈述更难。 并非如此。只需参数化各个 IN 令牌 (WHERE status IN (?, ?, ?))。 一个皱纹:列表大小可能会有所不同。动态列表大小存在问题,AFAIKpreparedStatement sql 可以有很长的“?”列表(即列表大小的上限);您可以设置前 3 个并使用 setNull 设置最后一个 upperbound-3。即:WHERE status IN (?,?,?,?,?,?,?,?,?,?) 这是一个完全解决的问题:javaranch.com/journal/200510/Journal200510.jsp#a2 这些方法中的任何一个都比原始字符串更好。 不,我认为这是“绝对”。没有例外。任何你认为是例外的事情实际上都是你需要用另一种方式解决的问题。【参考方案3】:

我认为您自己提出了解决方案:Parameterized Queries

您如何发现动态构建的查询比使用存储过程更快?一般来说,情况往往相反。

【讨论】:

啊,是的。一般来说是正确的,但在这些特定情况下,我们发现并非如此。情况如下:你有一个 DAO 方法,它有一个规范/标准对象,上面有 30 个字段。你可以有一个带有 30 个参数的存储过程,其 sql 如下所示:SELECT last_name, first_name FROM member WHERE (@pLastName IS NULL OR @pLastName=last_name) AND (@pFirstName IS NULL OR @pFirstName=first_name) AND ( @pSerialNbr 为空或@pSerialNbr=serial_nbr)与(@pZodiacSign 为空或@pZodiacSign=zodiac_sign)与(@pPartyRank 为空或@pPartyRank=party_rank) 根据我的经验,SQL 优化器/引擎在此类程序上的表现很差;他们重用一个非常通用的访问计划(通常是全表扫描),而不是即时识别以使用特定的索引。此外,一些值实际上是列表(即 'WHERE rank in (1,2,3)' )。我在一些地方以逗号分隔的列表传递给存储过程,解析并填充了一个临时表,并加入了临时表,但实际上这比带有 in 子句的简单 sql 执行 MUCH WORSE . 最后,根据我的经验总结一下:简单的 sql 性能最好。超花哨的 sql 导致超慢。优化器和访问计划生成器并不那么聪明。 (我们也支持一些不同的数据库,所以限制了我们可以提供多少提示) 如果必须为此使用动态生成的 SQL,请清理输入。我的意思是转义字符串,验证数字类型等。有很多预先存在的代码可以为你做这些。 如果您将字符串粉碎在一起在存储过程本身中,然后 exec() 结果,存储过程将无法保护您免受 SQL 注入。我已经看到这样做了。要强调的重要一点是参数化查询【参考方案4】:

回答你所有的问题:

这是 WAITFOR 攻击的可行解决方案吗?

没有。只需将 -- 添加到攻击字符串,它将忽略您的修复。

它能防御其他类似的漏洞吗?

没有。见上文。

我认为最好的选择是使用准备好的语句。更多的工作,但更少的脆弱性。

是的。您不会自己修复 SQL 注入。您使用已经存在的内容并且正确使用它,也就是说,通过参数化查询的任何动态部分。

另一种较小的解决方案是转义将要插入查询中的任何字符串,但是,您有一天会忘记一个,而您只需要一个就会受到攻击。

【讨论】:

【参考方案5】:

其他人都已经解决了这个问题(参数化!),但这里只是想谈谈几点:

这是 WAITFOR 攻击的可行解决方案吗? 它是否可以防御其他类似的漏洞?

不,它没有。 WAITFOR 技巧很可能只是用于“嗅探”漏洞;一旦他们找到了易受攻击的页面,他们可以在没有 DDL 或(非 SELECT 部分)DML 的情况下做很多事情。例如,考虑他们是否将以下内容作为 last_name 传递

' UNION ALL SELECT username, password FROM adminusers WHERE 'A'='A

即使在添加 AND 1 = 1 之后,您仍然会感到困惑。在大多数数据库中,您可以通过 SELECT 访问执行很多恶意操作...

【讨论】:

【参考方案6】:

如何关注 xkcd 并清理输入。一般情况下,您可以检查保留字,尤其是 WAITFOR。

【讨论】:

请不要。不要尝试使用一些不稳定的黑名单系统进行消毒。如果你对准备好的语句有一些神秘但强烈的厌恶,那么转义字符串。 我没有给你 -1,但看起来你的答案的第一句话可能需要 +1(因为它提到了 xkcd),但是你会看到第二句话。这就是一切崩溃的地方。 禁止保留关键字是一种策略,只有 TSA 能够负担得起花费数十亿美元并侥幸逃脱。 哈,我被 xkcd 的权威蒙蔽了双眼 :-) 使用准备好的语句显然是要走的路。

以上是关于防御“WAITFOR DELAY”sql 注入攻击?的主要内容,如果未能解决你的问题,请参考以下文章

SQL注入攻击和防御

SQL注入攻击和防御

SQL注入攻击与防范

SQL注入攻击威胁依旧,天融信TopWAF助力防御

防御与插入 SQL 注入攻击

PHP之防御sql注入攻击的方式