代码之家  ›  专栏  ›  技术社区  ›  Arseni Mourzenko

在架构/表名称中使用“[”和“]”字符时,如何避免SQL注入?

  •  2
  • Arseni Mourzenko  · 技术社区  · 14 年前

    我有几个上下文,其中表名或模式不是硬编码的,而是由管理员配置的,或者更糟的是,由用户输入生成的。

    由于case很容易(模式和表名都是纯英语的,没有数字和符号),因此只要禁止外部的任何字符,就很容易避免SQL注入 A-Z a-z 范围。但是,当应用程序必须处理任何Unicode字符(可以是模式或表名称的一部分)时,这种方法会很糟糕。

    现在,如果SQL查询使用 '[' ']' 要将名称包括到架构、表和列中,仅禁止 ']' 名称中的字符以避免SQL注入?

    例子:

    A'B是表的有效名称。所以:

    string tableNameFromUserInput = "A'B"; // Let's imagine it is a user input.
    using (SqlCommand getEverything = new SqlCommand(
        string.Format("select * from [dbo].[{0}]", tableNameFromUserInput),
        sqlConnection)
    {
        // Do stuff.
    }
    

    完全有效,并且没有理由阻止单引号字符。

    那么在下面的代码中是否存在SQL注入的风险?

    string tableName = UserInput.GetUnsafeInputFromUser();
    
    // Search for ']' character only.
    if (tableName.IndexOf(']') != -1)
    {
        throw new HackerDetectedException();
    }
    else
    {
        using (SqlCommand getEverything = new SqlCommand(
            string.Format("select * from [dbo].[{0}]", tableNameFromUserInput),
            sqlConnection)
        {
            // Do stuff.
        }
    }
    

    编辑:

    经过一番搜索,我发现了一篇关于 Delimited identifiers 在Microsoft SQL中。根据它:

    标识符的主体可以包含当前代码页中的任何字符组合,但分隔字符本身除外。

    顺便说一下,分隔标识符限制为128个字符。

    • 这个 必须禁止字符(或者,更好的是,替换为 ']]' ;见下面马克·拜尔斯的回答)。
    • 长度必须限制为128个字符(在上面的示例代码中没有这样做),
    4 回复  |  直到 14 年前
        1
  •  3
  •   Mark Byers    14 年前

    我想那是安全的。反斜杠等字符被视为文字字符,因此它们应该安全地包含在表名中。我能马上想到的唯一问题是 ] ,你已经不允许了。顺便说一下,包括 ] ]] ,所以你可以不完全否认 tableName.Replace("]", "]]") .

    但是为了安全起见,你应该按照你的建议使用白名单。要做到这一点,同时在表名中也允许使用unicode字符,您可能需要考虑使用正则表达式 @"^\w+$" 验证表名,因为它也接受unicode字符。

        2
  •  2
  •   TalentTuner    14 年前

    如果只是选择sql,即您不打算保存任何更改,则可以在try块中的事务中运行sql命令,并在finally块中回滚。

    这样,就可以在代码级别确保不会从代码运行任何其他ddl、dml。只有选定的状态将被执行。

    当您获取数据但不更新时,此particulalr startegey起作用。

       try
            {
                //Run command in transaction.
            }
            catch (Exception ex)
            {
                // rollback transaction
            }
    
            finally
            {
                // rollback transaction
            }
    

        3
  •  2
  •   Agent_9191    14 年前

    不确定内联SQL有多复杂,但为什么不直接将模式/表字符串从用户传递到 QUOTENAME()

        4
  •  0
  •   Woot4Moo    14 年前

    我认为以下内容可能会破坏您的数据库,可能是来自OWASP的以下内容:
    'and 1 in (select min(name ) from master.dbo.sysdatabases where name >'.' ) --'


    OWASP