【问题标题】:Is QuoteIdentifier enough to protect query from Sql injection attack?QuoteIdentifier 是否足以保护查询免受 Sql 注入攻击?
【发布时间】:2016-11-17 05:16:28
【问题描述】:

虽然参数是防止 Sql 注入的最佳方法,但在构建动态查询时有时我们不能使用它。例如,表/列/索引名称不能作为参数传入,只能作为纯文本传入。

好像

SqlCommandBuilder.QuoteIdentifier

是我能找到的唯一选择。调用这个方法是否足以保护我们自己?

MSDN 文档:

在正确的目录大小写中给定一个不带引号的标识符,返回 该标识符的正确引用形式。这包括正确 转义标识符中的任何嵌入引号。

例如是

"Select * FROM " + SqlCommandBuilder.QuoteIdentifier("CustomTable" + userInputText);

安全吗?

编辑:查询只是一个例子。我有兴趣了解是否可以进行 Sql 注入。

【问题讨论】:

    标签: c# sql-injection


    【解决方案1】:

    它不会保护您免受攻击者访问您不希望他们访问的表。

    如SQL系统表...

    【讨论】:

    • 这只是一个例子。我只是想知道是否可以进行 sql 注入
    • 这不是权限的用途吗?就此而言,任何 SQL 查询都不能防止用户访问他应该看到的表(再次授予权限......)
    【解决方案2】:

    这样做可能不安全。

    为了防止 SqlCommandBuilder.QuoteIdentifier 方法出现任何可能的安全问题,您需要做的就是从数据库中获取可用表名等的列表,并针对它们验证用户输入。

    编辑添加:我有理由怀疑QuoteIdentifier 是否完全安全:SqlCommandBuilder.QuoteIdentifier Method 的文档说(如您之前引用的):

    在正确的目录大小写中给定一个未引用的标识符,返回该标识符的正确引用形式。这包括正确转义标识符中的任何嵌入引号。

    该文档中没有任何地方说明如果在错误 目录案例(无论“目录案例”是什么)中给它一个不带引号的标识符会发生什么。或者如果标识符长于maximum allowed 会发生什么。当然,不能依赖未定义的行为。

    【讨论】:

    • 您能否提供一个示例来说明如何针对这种情况进行注入?
    • @Steve 不,我不能,但是有一些复杂的 SQL 注入攻击示例。我编辑了我的答案,提到了一种万无一失的方法。
    【解决方案3】:

    对我来说似乎很安全。另外,这可能是一个很好的参考:

    Sanitize table/column name in Dynamic SQL in .NET? (Prevent SQL injection attacks)

    【讨论】:

    • 表名可能包含特殊字符,所以我认为清理不是一个好的选择
    【解决方案4】:

    在表名字段中使用用户输入永远不会安全,无论您如何尝试检查它(除非您将条目限制为一组有限的名称或使用其他某种魔法)。

    即使删除引号,用户也可以输入:TableName; DROP DATABASE db;(SELECT * FROM <sensible table)

    可能的解决方案是:

    • 在用户无法修改选项的情况下使用 ComboBox 或等效项
    • 对照String[] 检查输入,其中包含所有允许表名(它们应与其中一个条目相同)

    如果作为表名的用户输入只是一个示例,但您要将输入用作SELECTWHERE 子句的一部分,那么您应该检查Bobby Tables

    引自网站:

    来自C# Online wiki 页面ASP.NET Security Hacks--Avoiding SQL Injection

    SqlCommand userInfoQuery = new SqlCommand(
        "SELECT id, name, email FROM users WHERE id = @UserName",
        someSqlConnection);
    
    SqlParameter userNameParam = userInfoQuery.Parameters.Add("@UserName",
        SqlDbType.VarChar, 25 /* max length of field */ );
    
    // userName is some string valued user input variable
    userNameParam.Value = userName;
    

    或者更简单:

    String username = "joe.bloggs";
    SqlCommand sqlQuery = new SqlCommand("SELECT user_id, first_name,last_name FROM users WHERE username = ?username",  sqlConnection);
    sqlQuery.Parameters.AddWithValue("?username", username);
    

    【讨论】:

    • 如果使用了 ComboBox,验证所选值仍然很重要,因为有多种方法可以修改它。
    • @AndrewMorton 这就是为什么我建议也使用带有允许值的String[],但是如果您开始这样想,如果用户篡改了程序集并删除了验证,它仍然可能会被破坏。
    【解决方案5】:

    您是否考虑过使用 OData?你可以传入文本、选择表格、索引等等。但是使用 OData,您可以通过这种方式选择要发布的表,并且它不能受到注入攻击,因为您必须明确允许更新和插入操作。

    http://www.odata.org/documentation/odata-version-2-0/uri-conventions/ https://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api

    【讨论】:

      猜你喜欢
      • 2012-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 2015-11-30
      • 2012-10-24
      • 2014-05-23
      • 1970-01-01
      相关资源
      最近更新 更多