参数真的足以阻止Sql注入吗?

时间:2008-11-20 20:06:44

标签: asp.net sql database sql-injection

我一直在向我的同事们讲道,在这里谈论在SQL查询中使用参数的好处,特别是在.NET应用程序中。我甚至还承诺给予他们免受SQL注入攻击的豁免权。

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

当然还有其他注意事项要确保Web应用程序是安全的(比如清理用户输入和所有内容),但现在我正在考虑SQL注入。我对MsSQL 2005和2008的攻击特别感兴趣,因为它们是我的主要数据库,但所有数据库都很有趣。

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

SELECT * FROM Table WHERE Name = 'a name'

我们这样做:

SELECT * FROM Table WHERE Name = @Name

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

9 个答案:

答案 0 :(得分:48)

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

您不能在占位符中使用函数,也不能将占位符用作列名或表名,因为它们会被转义并作为字符串文字引用。

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

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

答案 1 :(得分:12)

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

通过将文字值与SQL语法分开,查询参数有助于避免此风险。

'SELECT * FROM mytable WHERE colname = ?'

没关系,但还有其他目的是将数据插入到不能使用查询参数的动态SQL查询中,因为它不是SQL值,而是表名,列名,表达式或其他语法。

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

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

在这些情况下,补救措施是根据需要采用 FIEO

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

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

答案 2 :(得分:12)

这个帖子似乎有一些关于“参数化查询”定义的混淆。

  • 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();
}

答案 3 :(得分:10)

用于构造动态查询的字符串类型(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-injection攻击向量;

如果@ p1是以编程方式制定的,没有用户干预的能力那么它就不是潜在的sql-injection攻击载体

答案 4 :(得分:6)

缓冲区溢出不是SQL注入。

参数化查询可确保您对SQL注入安全。他们不保证您的SQL服务器中没有可能的漏洞形式的漏洞利用,但没有什么可以保证。

答案 5 :(得分:2)

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

答案 6 :(得分:1)

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

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

答案 7 :(得分:1)

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

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

答案 8 :(得分:1)

您可以运行动态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'