这个动态创建的 sql 有多脆弱?

Posted

技术标签:

【中文标题】这个动态创建的 sql 有多脆弱?【英文标题】:How vulnerable is the this dynamically created sql? 【发布时间】:2017-06-29 07:46:16 【问题描述】:

我可以在网上找到很多关于动态创建参数化查询的正确和安全方法的信息。但是这样的网站只讨论 where 子句的参数化。

那么,sql 语句的其他子句呢?请参阅以下内容:

       string sql = string.Format(@"                
            SELECT MIN(TableName) as TableName, 0
            FROM
            (
              SELECT 'Table A' as TableName, 0
              FROM 1
              UNION ALL
              SELECT 'Table B' as TableName, 0
              FROM 2
            ) tmp
            GROUP BY 0
            HAVING COUNT(*) = 1", columnList, tableA, tableB);

我正在构建一个语句,其中已对以下内容进行了参数化:

    select 子句中的项目 from 子句中的表名

问题: 这对可能造成一些损害的 sql 注入有多脆弱?

无论如何,我想不出恶意黑客可以注入 sql,从而生成格式正确、可执行的 sql。不过话说回来,我不是 sql 专家。

【问题讨论】:

只要查询的任何部分来自不受信任的来源,它就容易受到 SQL 注入攻击。例如,如果您在tableA = someBool ? "foo" : "bar"; 上方有某行代码,则没有风险,因为它将是 foo 或 bar。但是,如果您从某些表单提交或您无法控制的其他外部来源获得tableA 的值,那么您就有风险了。查询中使用的其他变量也是如此。 使用参数化查询,推荐方法 @EhsanSajjad sql 参数不能用于表名和列名。 其他 cmets 出现了,但只是为了扮演魔鬼的拥护者,假设有人可以让您的代码以 columnList = "null from myTable; drop table myTable; ..." 的值执行,而其余的 sql 是否是无关紧要的垃圾与否。如果引擎被告知要运行它直到它失败,你可能会遇到问题。 那是更正问题,不是愚蠢的问题! :) 答案是“也许”。在将变量传递给“查询构建器”之前,您确实必须自己确定变量如何分配其值。如果最终用户甚至其他开发人员可以操纵这些值,您应该通过清理输入来保护自己。如果你要清理输入,参数化查询就是这样做的方法。这完全取决于您的具体情况以及最终可能进入查询的值。 【参考方案1】:

这真的取决于columnListtableAtableB 的来源。如果它们来自您的代码,没有用户输入,那么它是非常安全的。如果用户指定表名,你必须准备好迎接Little Bobby Tables。

在我公司的主要 c# 应用程序中,我们使用类似的方法来声明列,但 SQL 表中的列是在该表的类中定义的,因此我们可以从该类构建选择、添加、更新和创建表字符串。用户永远无法定义这些列。

【讨论】:

【参考方案2】:

正如@Andrew 在他的回答中所说,如果参数不受任何用户输入的影响,或者得到验证/清理,那应该没问题。

回答您关于可能格式正确的 SQL 语句的观点... 唯一引起关注的领域是潜在的转义字符(例如分号,从技术上讲,它可以放置在命令块中的任何位置)和/或其他东西在声明的12 部分格式良好。

【讨论】:

我认为 0 也同样容易受到攻击。 * FROM TableA; DROP TABLE TableB; SELECT * @Andrew 我认为这种攻击/利用形式是转义字符(分号);从技术上讲,它可以在命令块中的任何位置。我会更新我的答案,因为您的评论也是正确的。

以上是关于这个动态创建的 sql 有多脆弱?的主要内容,如果未能解决你的问题,请参考以下文章

使用动态 sql 为 select 语句创建列

创建一个表,其中动态 PL/SQL 中的“日期条件”

超全MyBatis动态SQL详解!( 看完SQL爽多了)

创建动态 SQL 查询的问题

动态创建列sql

在 MySQL 中使用动态 SQL 创建游标