【问题标题】:Secure full where statement when it comes as a string以字符串形式出现时确保完整的 where 语句
【发布时间】:2018-07-15 05:12:24
【问题描述】:

我有以下 C# 函数

        SomeFunction(string table, string column, string where) { 
            Sql sql = new Sql("SELECT ");

            // [...] validate table and column values

            sql.Append(column);
            sql.Append(" FROM ");
            sql.Append(table);
            sql.Append(" WHERE ");
            sql.Append(where); // This is the issue
        }

如您所见,这很糟糕,我正在处理这个非常旧的遗留代码并更改函数签名以及客户使用它的方式是不可行的。我要做的是确保“where”条款的安全。该子句可以包含任意数量的条件和数据类型。

我有很多想法,但我认为它们不是一个好的解决方案,我认为这需要一个正确编写和测试的代码,但如果我自己做它可能会出现漏洞。以下是一些想法:

  • 用 char '=' 分割字符串 -> 如果不是条件运算符怎么办
  • 查找字符串是否包含分号 -> SELECT 子句仍然容易受到攻击,并且可能其中一个条件包含该字符,因此它会给出误报

如果您有任何想法/建议/指出正确的方向,我将不胜感激。

【问题讨论】:

  • 请注意,tablecolumn 也是 攻击媒介,除非您明确声明它们是可信值。
  • 获取where clause 并阅读它的整个文档(它接受的谓词),并以此为基础。
  • 还有in><like等。此外,不同的数据库可能支持不同的东西——例如 MySql 支持 (col1, col2) in (value1, value2) 而 SQL Server 会抛出语法错误。有多少客户端可以运行此方法?
  • 这非常复杂,因为您必须(基本上)解析任意表达式,这比转义值要困难得多。确定结果语句是否至少是一条语句相当容易,但这也不能完全防止 SQL 注入,因为它仍然可以选择任意表和列(包括系统表、用户帐户等)。首先,尝试 非常很难以不易受攻击的方式限制输入。特别是,用户实际上如何使用WHERE?他们实际访问的是哪些表?

标签: c# where sql-injection where-clause sanitization


【解决方案1】:

如果where 子句当前基于预先组合的string,那么坦率地说,我认为尝试“保护”它不是一种可行的方法。这在理论上是可能的,但如果组合和妥协(注入)where 子句是合法的(但滥用),则任何解析 SQL 的尝试都将失败。那时:您已经忘记了最初的意图。这就是 SQL 注入的全部要点:生成的 SQL 是有效的 SQL - 所以你很难区分 where Name = 'Fred Orson' -- check name(可能没问题)和 where Name = 'Fred' Or 1=1 --'(注入 - 查询扩大)。

所以:虽然我承认你说:

更改函数签名和客户端使用它的方式是不可行的。

更改函数签名并不能真正帮助您解决问题。试图检测某些模式只是一场军备竞赛,你需要每次都赢,而攻击者只需要赢一次。

如果是我,我会做这样的事情:

[Obsolete("Please specify parameters separately - use 'null' if no parameters are needed")]
SomeFunction(string table, string column, string where) {
    return SomeFunction(table, column, where, null);
}
SomeFunction(string table, string column, string where, object args) {
    // ...
}

并使用“Dapper”之类的方法来组合来自args 参数的参数 - 或者仅使用“Dapper”本身来运行查询,并免费使用该功能。

这种方法:

  • 防止添加危险 API 的新用途
  • 让现有代码暂时继续工作
  • 但可让您通过查看警告来跟踪有多少未解决的问题调用

编辑:注意:args 参数的point是允许调用者参数化他们的输入,即

string name = ...
var users = SomeFunction("Users", "Id", "Name=@name", new { name });

使用SomeFunction 分解args 并从args 的属性中添加参数名称/值对(如果它不为空)。有多种组合参数集的方法,但这里显示的方法简单且易于正确实现 - 这对我来说是一个明显的胜利。

【讨论】:

  • @ZoharPeled 不过可以参数化;我会更明确的
  • 是的,它可以被参数化,但必须它是?
  • @ZoharPeled 如果您希望您的系统是安全的,那么:。当然,除了安全性之外,参数化还解决了广泛的其他问题,这使得它值得即使没有安全方面。如果您说“但是有人可以通过注入的版本并将null 作为参数传递”-他们是的:没有多少代码可以防止愚蠢。在这一点上,这是开发和审查过程的失败。
  • 我很清楚参数化查询的好处,这不是我要问的。我要问的是什么阻止了用户这样做:var users = SomeFunction("Users", "Id", "Name='name' or 1=1")?
  • @dasjkdj 理论上你甚至不需要 - 你可以添加你在args 上找到的所有内容;但这可能会导致发送的值超出需要。 “Dapper”这样做的方式只是检查 - 对于在 args 上找到的每个键 foo,查询是否包含 @foo:foo?foo 中的任何一个? - 见github.com/StackExchange/Dapper/blob/master/Dapper/… - 如果是:添加它;如果不是:它没有。说真的,也许可以简单地让“Dapper”来完成这里的所有工作。
猜你喜欢
  • 2014-05-27
  • 2011-05-23
  • 1970-01-01
  • 2016-12-20
  • 1970-01-01
  • 1970-01-01
  • 2019-06-04
  • 2017-04-24
  • 1970-01-01
相关资源
最近更新 更多