代码之家  ›  专栏  ›  技术社区  ›  Rune Grimstad

参数是否足以防止SQL注入?

  •  81
  • Rune Grimstad  · 技术社区  · 17 年前

    我一直在向我的同事和这里的其他人宣扬在SQL查询中使用参数的好处,特别是在.NET应用程序中。我甚至承诺他们对SQL注入攻击具有免疫力。

    但我开始怀疑这是否真的是真的。是否有任何已知的SQL注入攻击将对参数化查询成功?例如,您可以发送一个导致服务器上缓冲区溢出的字符串吗?

    当然,为了确保Web应用程序是安全的,还需要考虑其他一些因素(比如清理用户输入和所有这些东西),但是现在我正在考虑SQL注入。我对针对MSSQL2005和2008的攻击特别感兴趣,因为它们是我的主要数据库,但所有数据库都很有趣。

    编辑:澄清参数和参数化查询的含义。通过使用参数,我的意思是使用“变量”而不是在字符串中构建SQL查询。
    所以不要这样做:

    SELECT * FROM Table WHERE Name = 'a name'
    

    我们这样做:

    SELECT * FROM Table WHERE Name = @Name
    

    然后在查询/命令对象上设置@name参数的值。

    9 回复  |  直到 15 年前
        1
  •  48
  •   Adam Bellaire    16 年前

    占位符 足以防止注射。您可能仍然对缓冲区溢出开放,但这与SQL注入完全不同(攻击向量不是SQL语法而是二进制)。由于传递的参数都将被正确转义,因此攻击者无法传递将被视为“活动”SQL的数据。

    不能在占位符内使用函数,也不能将占位符用作列或表名,因为它们是以字符串文本形式转义和引用的。

    但是,如果您使用 参数 作为A的一部分 字符串连接 在动态查询中,您仍然容易被注入,因为您的字符串不会被转义,但会是文字。使用其他类型的参数(如整数)是安全的。

    也就是说,如果使用输入来设置 security_level 这样,就有人可以让自己成为系统中的管理员,并拥有一个免费的。但这只是基本的输入验证,与SQL注入无关。

        2
  •  12
  •   Bill Karwin    17 年前

    不,在您将未验证的数据插入到SQL查询中时,仍然存在SQL注入的风险。

    查询参数通过将文字值与SQL语法分开来帮助避免这种风险。

    'SELECT * FROM mytable WHERE colname = ?'
    

    这很好,但是在动态SQL查询中插入数据还有其他目的,即不能使用查询参数,因为它不是SQL值,而是表名、列名、表达式或其他语法。

    'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')'
    ' ORDER BY ' + @colname'
    

    不管您是使用存储过程还是直接从应用程序代码执行动态SQL查询,这都无关紧要。风险仍然存在。

    在这些情况下,补救办法是 菲欧 必要时:

    • 过滤器输入: 在插入数据之前,请验证数据看起来像合法的整数、表名、列名等。

    • 逃逸输出: 在这种情况下,“输出”意味着将数据放入SQL查询中。我们使用函数来转换在SQL表达式中用作字符串文本的变量,以便对字符串中的引号和其他特殊字符进行转义。我们还应该使用函数来转换将用作表名、列名等的变量。至于其他语法,比如动态地编写整个SQL表达式,这是一个更复杂的问题。

        3
  •  12
  •   HTTP 410    17 年前

    在这个线程中,关于“参数化查询”的定义似乎有些混淆。

    • SQL,例如接受参数的存储过程。
    • 使用DBMS参数集合调用的SQL。

    根据前面的定义,许多链接都显示了有效的攻击。

    但“正常”的定义是后者。根据这个定义,我不知道有什么SQL注入攻击会起作用。这并不意味着没有,但我还没有看到。

    从评论中,我没有足够清晰地表达自己,因此这里有一个希望更清楚的例子:

    这种方法 打开SQL注入

    exec dbo.MyStoredProc 'DodgyText'
    

    这种方法 不是 打开SQL注入

    using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
        newParam.Value = "DodgyText";
        .....
        cmd.Parameters.Add(newParam);
        .....
        cmd.ExecuteNonQuery();
    }
    
        4
  •  10
  •   Jonathan Leffler    17 年前

    用于构造动态查询的任何字符串类型(varchar、nvarchar等)的SQL参数仍然容易受到攻击

    否则,参数类型转换(例如到int、decimal、date等)应消除通过参数注入SQL的任何尝试。

    编辑:一个示例,其中参数@p1是表名

    create procedure dbo.uspBeAfraidBeVeryAfraid ( @p1 varchar(64) ) 
    AS
        SET NOCOUNT ON
        declare @sql varchar(512)
        set @sql = 'select * from ' + @p1
        exec(@sql)
    GO
    

    如果从下拉列表中选择@p1,则它是潜在的SQL注入攻击向量;

    如果@p1是以编程方式制定的,并且没有用户干预的能力,那么它不是潜在的SQL注入攻击向量

        5
  •  6
  •   Blorgbeard    17 年前

    缓冲区溢出不是SQL注入。

    参数化查询可以保证您对SQL注入的安全性。它们不能保证在您的SQL Server中不存在以bug形式存在的可能的漏洞利用,但是没有任何东西可以保证这一点。

        6
  •  2
  •   HLGEM    17 年前

    如果以任何方式使用动态SQL,则数据是不安全的,因为权限必须在表级别。是的,您限制了该特定查询的注入攻击类型和数量,但不限制用户在找到进入系统的方法时可以获得的访问权限,并且您完全可以让内部用户访问他们不应该访问的内容,以便进行欺诈或窃取个人信息以进行销售。任何类型的动态SQL都是一种危险的实践。如果使用非动态存储进程,则可以在进程级别设置权限,除进程定义的权限外,任何用户都不能执行任何操作(当然,系统管理员除外)。

        7
  •  1
  •   Booji Boy    17 年前

    存储过程可能容易受到通过溢出/截断进行的特殊类型的SQL注入的攻击,请参见:此处通过数据截断启用的注入:

    http://msdn.microsoft.com/en-us/library/ms161953.aspx

        8
  •  1
  •   nos    17 年前

    请记住,使用参数,您可以轻松地存储字符串,如果没有任何策略,可以说用户名,“);删除表用户;—”

    这本身不会造成任何伤害,但您最好知道在应用程序中该日期在何处以及如何进一步使用(例如存储在cookie中,稍后检索以执行其他操作)。

        9
  •  1
  •   Mohamed Abbas    15 年前

    您可以运行动态SQL作为示例

    DECLARE @SQL NVARCHAR(4000);
    DECLARE @ParameterDefinition NVARCHAR(4000);
    
    SELECT  @ParameterDefinition = '@date varchar(10)'
    
    SET @SQL='Select CAST(@date AS DATETIME) Date'
    
    EXEC sp_executeSQL @SQL,@ParameterDefinition,@date='04/15/2011'