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


83

我一直在向我的同事和SO讲这件事,说明在SQL查询中,尤其是.NET应用程序中使用参数的好处。我什至甚至承诺它们可以抵抗SQL注入攻击。

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

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

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

SELECT * FROM Table WHERE Name = 'a name'

我们这样做:

SELECT * FROM Table WHERE Name = @Name

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


我们应该弄清楚参数的含义(正如乔纳森·莱夫勒(Jonathan Leffler指出)一样)-我当时在考虑存储过程参数,但是还有?parms and {0} parms ...
Steven A. Lowe

说起来容易得多,我们不使用串联来构建查询。

由于标签是asp.net,因此我想您正在构建Web应用程序。在这种情况下,您还应该注意XSS攻击以及其他一些攻击
Spikolynn

Answers:


50

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

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

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

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


关键是要了解Steve Lowe的答案所引起的问题,该问题也在@mikekidder引用中指出-无论在应用程序还是服务器中,无论动态SQL处于什么位置,您都必须警惕。动态SQL是危险的-但可以使其变得安全。
乔纳森·莱夫勒

“攻击者无法以任何方式传递将被视为“实时” SQL的数据”。-这不是真的,请参阅以下示例。
Booji Boy

以下所有示例均定义“参数化查询”以表示SQL代码接受参数。普通定义是使用DBMS参数集合的查询。除DBMS错误外,后一种技术可防止SQL注入。
HTTP 410

2
我已经阅读了每个链接。请引用任何指向DBMS Parameters集合的有效注入攻击的链接。的确,您发布的链接将这种方法称为失败SQL注入(请参阅“使用类型安全的SQL参数”部分)。
HTTP 410

嗨!您能否提供指向Oracle SQL语法或类似内容的链接来证明这一答案。我了解这一点,并完全同意您的意见,但是拥有与文档,语法等的正式链接将非常棒。BestRegards,Raimbek
Raimbek Rakhimbek

13

不,将未验证的数据插入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表达式,这是一个更复杂的问题。


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

您能否阐明DBMS Parameters集合的含义,而不是接受参数的过程?
符文格里姆斯塔德

符文,请阅读此链接的“使用类型安全的SQL参数”部分:msdn.microsoft.com/en-us/library/ms161953.aspx
HTTP 410

我的回答是针对Rune的原始问题,然后使用更新对其进行了编辑。
mikekidder

我已经阅读并重读了有关sql注入的msdn-article,但我仍然看不到存储过程所采用的参数与动态查询所采用的参数之间有何区别。除了动态查询是动态的之外。您仍然必须绑定参数,对吗?
符文格里姆斯塔德

绑定才是最重要的。如果直接使用参数调用存储的proc,则不会进行任何输入过滤。但是,如果通过(例如)使用.NET中的SqlCommand参数集合进行绑定,则所有参数都将被过滤并视为纯文本。
HTTP 410

10

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

否则,参数类型转换(例如,转换为int,十进制,日期等)应消除通过参数注入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注入攻击媒介


没有; 关键是传递给DBMS的字符串不是SQL语句的一部分。因此,字符串中的值对SQL的解释没有影响-只是对SQL引用的值没有影响。
乔纳森·勒夫勒

这也是我看到参数的方式。他们应该防止此问题。
符文格里姆斯塔德

2
例如,如果您要将字符串传递给使用它来运行诸如sp_executeSql(SQL Server)之类的sp的Steven,那么您仍然有SQL注入风险。
alexmac

@Steven:这不是SQL的参数;您将必须有一个占位符(问号)来代替字符串连接。并且SQL不允许您通过占位符指定表名。那是一个纯SQL注入漏洞-原始问题。
乔纳森·莱夫勒

@Steven:也许“参数”一词经常被重载。:D
乔纳森·勒夫勒

6

缓冲区溢出不是SQL注入。

参数化查询确保您可以安全地进行SQL注入。他们不保证SQL服务器中的bug形式不存在漏洞,但是没有任何东西可以保证。


2

如果以任何形式或形式使用动态sql,则数据是不安全的,因为权限必须在表级别。是的,您已经限制了来自该特定查询的注入攻击的类型和数量,但没有限制用户在发现某种方式进入系统后可以获得的访问权限,并且内部用户完全不愿访问他们不应该访问的内容进行欺诈或窃取个人信息以进行出售。任何类型的动态SQL都是危险的做法。如果使用非动态存储的proc,则可以在过程级别设置权限,除了proc定义的用户(当然,系统管理员除外)之外,任何用户都不能做任何事情。


因此,这里的教训是,如果必须使用动态sql,请仅在存储过程内部使用。+1好建议!
史蒂文·劳

1
不能-通过将未经验证的数据插值到动态查询中,存储的proc中的动态SQL仍会引入SQL注入缺陷。
Bill Karwin

没有教训,那就是永远不要使用动态SQl
HLGEM

@HLGEM-是的,汽车会发生交通事故,所以我们绝对不要使用汽车。
Bill Karwin

但是,存储的proc中的动态SQL在默认情况下是在调用者的许可下运行的,而不像静态的SQL在存储的proc所有者的许可下运行。这是一个重要的区别。
HTTP 410

1

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

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


如果您详细阅读该文章,您会发现使用SQL Server的Parameters集合可以防止此攻击。这就是“参数化查询”的常规定义-它使用DBMS的Parameters集合。
HTTP 410

1

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

这本身不会造成任何伤害,但是您最好知道该日期在应用程序中的位置和使用方式(例如存储在Cookie中,以后再检索以用于其他用途)。


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'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.