当前位置: 主页 > 网络知识 > 网络安全 > 新型SQL截断攻击和防御方法

新型SQL截断攻击和防御方法

时间:2010-6-11来源:互联网 点击:

  利用 SQL 注入方法的漏洞攻击已经引起了广泛关注,因为这些漏洞能够穿过防火墙和入侵检测系统,从而破坏您的数据层。无论是第一级还是第二级注入攻击,如果您看一下基本的代码模式,它与其他任何注入攻击问题都类似,即您在构造语句时都使用了不受信任的数据。大多数开发人员已经开始通过在后端使用参数化 SQL 查询和存储过程来减少 Web 前端的这些漏洞,但有些情况下,开发人员仍使用动态构建的 SQL,例如根据用户输入或为 C/C++ 编写的应用程序构造数据定义语言 (DDL) 语句时。

  在本文中我将讨论一些新观点,其结果可能会修改 SQL 语句或注入 SQL 代码,即使代码对分隔字符进行了转义。我首先介绍一些构建分隔标识符和 SQL 字符串的最佳实践,然后我将介绍攻击者注入 SQL 代码的几种新方法,以帮助您保护您的应用程序。

  分隔标识符和字符串

  在 SQL Server™ 中,有两种字符串变量:唯一可识别 SQL 对象(如表、视图和存储过程)的 SQL 标识符,以及用于表示数据的字符串。分隔 SQL 标识符的方法与分隔数据字符串的方法不同。我们将讨论需要使用这些数据变量的动态 SQL 构建方法的最佳实践。

  如果 SQL 对象名使用了关键字,或者对象名中包含了特殊字符,则您需要使用分隔标识符。假如您需要删除 my_dbreader 登录名,则可以执行以下语句:

DROP LOGIN my_dbreader

  如果您试着删除一个使用 DROP 作为其名称(也是关键字)的登录名会怎样?如果您使用以下 SQL 语句,SQL Server 会返回一个语法错误。

DROP LOGIN DROP如果您要删除像 my][dbreader 这样的登录名又会怎样?这也会引发语法错误。

  在上面两个例子中,由于登录名为关键字或包含特殊字符,因此您需要提供一些开始和结束标记,以便 SQL Server 可以识别 SQL 语句中的对象名。

  您可以使用双引号或方括号作为 SQL 标识符的分隔符,而在 QUOTED_IDENTIFIER 设置(一种基于连接的设置)启用时您可以只使用双引号。为简便起见,最好始终使用方括号。

  要成功删除 DROP 登录名,您可以使用方括号来构造您的 SQL 语句:

DROP LOGIN [DROP]但以下语句会怎样?DROP LOGIN [my][dbreader]在这种特殊情况下,由于登录名 my][dbreader 中包含分隔字符,因此 SQL 会认为 [my] 是登录名,因为它被包含在方括号内。由于 [dbreader] 跟在登录名后面,因此该语句并不构成正确的 SQL 语句,会导致语法错误。您可以通过用另一个右方括号对上面的右方括号进行转义来解决这一问题。因此,如果您执行以下语句,SQL Server 将成功删除 my][dbreader 登录名:DROP LOGIN [my]][dbreader]转义机制只是使右方括号的出现次数增加了一倍。您无需改动其他字符,包括左方括号。

  准备分隔字符串与准备分隔 SQL 标识符类似,主要区别就是需要使用的分隔字符。在介绍与构建分隔字符串相似的规则之前,先来看以下几个例子。

  假设您希望创建 dbreader 登录名,密码是 P@$$w0rd。您会使用以下 SQL 语句:

CREATE LOGIN [dbreader] WITH PASSWORD = ‘P@$$w0rd‘在该语句中,P@$$w0rd 是由单引号分隔的字符串数据,因此 SQL 知道该字符串从哪里开始,到哪里结束。但如果字符串数据中包含单引号会怎样?SQL Server 会引发一个错误,因为该语句为无效语句:CREATE LOGIN [dbreader] WITH PASSWORD = ‘P@$$‘w0rd‘您需要对字符串中出现的所有单引号进行转义,构造有效的 SQL 语句:CREATE LOGIN [dbreader] WITH PASSWORD = ‘P@$$‘‘w0rd‘当您执行该语句时,SQL Server 将创建 dbreader 登录名,密码为 P@$$‘w0rd。

  您还可以使用双引号作为分隔符,但正如我前面提到的,这种方法是否成功完全取决于 QUOTED_IDENTIFIER 设置是否已开启。因此,最好始终使用单引号作为字符串的分隔符。

  T-SQL 函数

  可以看出,处理标识符和字符串的规则相对比较简单,如果您预先知道该字符串,可以手动对其进行分隔。但如果您要根据用户输入构建动态的 T-SQL 语句,该怎么办?您需要通过自动的方法来完成。两种 T-SQL 函数可帮您准备分隔字符串,它们是 QUOTENAME 和 REPLACE。

  QUOTENAME 会返回一个 Unicode 字符串,并添加了分隔符,以使该输入字符串成为有效标识符。QUOTENAME 函数使用以下语法:

QUOTENAME ( ‘string‘ [ , ‘delimiter‘ ] )您可以将要分隔的字符串和一个用作分隔符的单字符字符串传给 QUOTENAME。分隔符可以是方括号、单引号或双引号。

  此函数主要用于准备分隔 SQL 标识符,因此它只接受 sysname 类型,在 SQL Server 中为 nvarchar(128)。您还可以使用此函数准备分隔 SQL 字符串,但由于参数长度的限制,因此它支持的字符串长度最多为 128 个字符(在这一点上,REPLACE 函数可发挥其用途)。图 1 显示了 sp_addlogin 如何使用 QUOTENAME 来准备分隔登录名和密码字符串。可以看出,由于 @loginname 和 @passwd 均为 sysname 类型,因此可使用 QUOTENAME 函数准备分隔 SQL 标识符和分隔字符串。因此,即使有人传递的是 @loginname = ‘my[]dbreader‘ 和 @passwd = ‘P@$$‘‘w0rd‘,也不会有任何 SQL 注入机会,因为 QUOTENAME 对分隔字符进行了适当转义:

create login [my[]]dbreader] with password = ‘P@$$‘‘w0rd‘

SQL 安全性: 新型 SQL 截断攻击和防御方法Figure1Delimiting Strings with QUOTENAME

create procedure sys.sp_addlogin
  @loginame    sysname
  ,@passwd     sysname = Null
  ,@defdb     sysname = ‘master’   
  ,@deflanguage  sysname = Null
  ,@sid      varbinary(16) = Null
  ,@encryptopt   varchar(20) = Null
AS
  -- SETUP RUNTIME OPTIONS / DECLARE VARIABLES --
  -- some code ----
  set @exec_stmt = ‘create login ‘ + quotename(@loginame, ‘[‘)
  if @passwd is null
    select @passwd = ‘‘
  if (@encryptopt is null)
    set @exec_stmt = @exec_stmt + ‘ with password = ‘ +
      quotename(@passwd, ‘‘‘‘)
  else
  -- some code
GO

  REPLACE 函数会将某个给定字符串的所有出现之处全部替换为指定的替代字符串。与 QUOTENAME 不同,REPLACE 函数对其接受的参数没有长度限制:

REPLACE ( ‘string1‘ , ‘string2‘ , ‘string3‘ )

  REPLACE 带有三个字符串:string1 是要编辑的表达式,string2 是 string1 中要被替换的项,string3 是用于取代 string2 的项。任何字符串表达式都可由字符或二进制数据组成。

  要准备分隔 SQL 字符串,您可以使用 REPLACE 使单引号的出现次数增加一倍,但您需要手动添加分隔符(开始和结束的单引号)。图 2 显示了 sp_attach_single_file_db 如何使用此函数准备一个文件的已转义的物理名称。由于 @physname 是 nvarchar(260),因此您无法使用 QUOTENAME 准备分隔字符串,这就是为何要使用 REPLACE 的原因。因此,即使有人传递带单引号的字符串,他们也无法打破 SQL 语句,注入任何 SQL 代码。

SQL 安全性: 新型 SQL 截断攻击和防御方法Figure2Delimiting Strings with REPLACE

create procedure sys.sp_attach_single_file_db
  @dbname sysname,
  @physname nvarchar(260)
as
  declare @execstring nvarchar (4000)
  -- some code --
  select @execstring = ‘CREATE DATABASE ‘
    + quotename( @dbname , ‘[‘)
    + ‘ ON (FILENAME =‘
    + ‘‘‘‘
    + REPLACE(@physname,N’’’’,N’’’’’’)
    + ‘‘‘‘
    + ‘ ) FOR ATTACH’
  EXEC (@execstring)
  -- some code --
GO

.
分页: [1] [2] [3] [4]
TAG: SQL攻击 防御
推荐内容最近更新人气排行