ITPub博客

首页 > 数据库 > SQL Server > SQL Server 2000的安全策略(二)

SQL Server 2000的安全策略(二)

原创 SQL Server 作者:kitesky 时间:2005-04-14 10:13:25 0 删除 编辑

8、以最低权限帐户身份进行开发

通常情况下,保护开发服务器安全的最佳方法,就好似它正在生产环境中运行那样对它进行保护。您离这个目标越接近,那么就可以越自信于您开发的代码可以在一个安全的生产环境中正常运行。
    在开发过程中,大家都着迷于使用具有 sysadmin 或 dbo SQL Server 权限的帐户,直到部署之前才转换为一个权限更低的帐户。使用这种方法存在着一个问题:将设计人员的权限集还原为最低的所需权限集与在开发应用程序过程中编写这些权限集相比,前者要困难得多。
         鉴于部署应用程序之前您要决定可以取消哪些权限,所以请不要使用 SQL sysadmin 帐户开发 T-SQL 代码。如果使用 SQL sysadmin 帐户,可能会造成这样的结果,即应用程序会以比所需权限更多的特权帐户运行。因此,开发时请改为使用具有最低权限的帐户。
         使用这样的帐户进行开发时,您会逐渐地升高授予的特定权限,以 EXEC(执行)一些必需的存储过程、从某些表进行 SELECT(选择)等。请编写这些 GRANT 语句,以便可以将同样的最低权限轻松部署到生产环境中,而不会出现任何基于猜测的操作。
         这种理念同样适用于测试。执行临时测试以及结构更加复杂的测试时,所使用帐户拥有的权限集和用户权限应该与在生产环境中所使用帐户拥有的权限集和用户权限完全相同。
在开发过程中使用最低权限帐户的另一个优点在于,您可以避免不小心编写出需要危险权限或过高权限的代码。例如,假设您需要在 T-SQL 中与第三方 COM 组件进行交互。为此,一种方法是发送一个 SQL 批处理命令,它直接调用 sp_OACreate 和 sp_OAMethod 来操纵该 COM 对象。在应用程序使用 sysadmin 帐户连接 SQL Server 的开发环境中,上述方法效果很好。但是,当您尝试将已经开发完成的应用程序准备用于生产部署时,您就会发现如果使用权限较低的帐户,那么该方法不会奏效。为了让该应用程序能够使用非 sysadmin 帐户在生产环境中正常运行,您必须针对 sp_OACreate 显式授予 EXECUTE 权限。请考虑一下,如果某个用户最终找到了一个方法,可以使用该应用程序登录执行任意代码,并利用此权限针对 SQL Server 实例化一个类似Scripting.FileSystemObject 的 COM 对象,将会产生怎样的安全隐患?

9T-SQL脚本安全

有一些 T-SQL 命令和扩展存储过程,它们具有自己独特的安全考虑事项。

1sp_OACreate 及其相关的系统过程系列

例如 sp_OAMethodsp_OAGetProperty 等。通过授予应用程序登录直接访问这些过程的权限,会带来该安全问题。为了避免此问题的发生,请绝对不要编写直接调用 sp_OA 过程的应用程序代码,而要将对这些过程的所有引用都打包在您自己的 T-SQL 存储过程中,并只授予访问这些包装存储过程的权限。另外,请不要允许应用程序代码将 COM 对象或方法的名称作为可由包装过程无条件调用的字符串进行传递。

2 xp_cmdshell

这个系统存储过程可以运行任何可执行文件或系统命令。由于一些很显然的原因,xp_cmdshell 上的 EXEC 权限默认情况下仅为 sysadmin 用户,必须显示地为其他用户授予该权限。如果您需要应用程序在 SQL Server 上运行某个特定的命令或实用程序,则请注意,不要在应用程序中构建一个 xp_cmdshell 直接访问的相关内容。这样的风险与直接访问 sp_OACreate 的风险相似。一旦为某个帐户授予了 xp_cmdshell EXEC 权限,该帐户不但能够执行您希望其访问的特定命令,而且能够执行成百上千个操作系统命令和其他可执行文件。与 sp_OACreate 相似,始终将 xp_cmdshell 调用打包在另一个存储过程中,避免直接在 xp_cmdshell 上授予 EXECUTE 权限。

您还应该避免将任何用户提供的字符串参数或者应用程序提供的字符串参数与将要通过 xp_cmdshell 执行的命令进行串联。如果无法达到上述要求,则必须了解,有一个专门针对 xp_cmdshell 的潜在的代码注入式攻击(至少在 SQL Server 中)。以下面的存储过程为例:

 CREATE PROCEDURE usp_DoFileCopy @filename varchar(255)
        AS
        DECLARE @cmd varchar (8000)
        SET @cmd = 'copy srcshare' + @filename + ' destshare'
        EXEC master.dbo.xp_cmdshell @cmd
        GO
        GRANT EXEC ON usp_DoFileCopy TO myapplogin

通过将 xp_cmdshell 调用打包在您自己的存储过程中并只针对该 usp_DoFileCopy 存储过程授予 EXEC 权限,您已经阻止了用户直接调用 xp_cmdshell 以执行任意命令。然而,以下面的 shell 命令插入为例:

EXEC usp_DoFileCopy @filename = ' & del /S /Q destshare & '

使用这个 @filename 参数,将要执行的字符串为 copy srcshare & del /S /Q destshare & destshare和号 (&) 被操作系统命令解释器处理为命令分隔符,因此该字符串将被 CMD.EXE 视为三个互不相关的命令。其中第二个命令 (del /S /Q destshare) 将尝试删除 destshare 中的所有文件。通过利用该存储过程中某个 shell 命令插入漏洞,用户仍然可以执行任意操作系统命令。针对此类攻击进行防御的一种方法是将命令字符串打包在一个 T-SQL 函数中,如下所示。这个用户定义的函数会添加 shell 转义符 (^),对出现的任何 & 字符或其他具有特殊意义的字符进行转义。
----------------------------------------------------------------------
-- Function: fn_escapecmdshellstring
-- Description: Returns an escaped version of a given string
--              with carets ('^') added in front of all the special
--              command shell symbols.
-- Parameter: @command_string nvarchar(4000)
----------------------------------------------------------------------
CREATE FUNCTION dbo.fn_escapecmdshellstring (
  @command_string nvarchar(4000)) RETURNS nvarchar(4000) AS
BEGIN
  DECLARE @escaped_command_string nvarchar(4000),
    @curr_char nvarchar(1),
    @curr_char_index int   
  SELECT @escaped_command_string = N'',
    @curr_char = N'',
    @curr_char_index = 1
  WHILE @curr_char_index <= LEN (@command_string)
  BEGIN
    SELECT @curr_char = SUBSTRING (@command_string, @curr_char_index, 1)
    IF @curr_char IN ('%', '<', '>', '|', '&', '(', ')', '^', '"')
    BEGIN
      SELECT @escaped_command_string = @escaped_command_string + N'^'
    END
    SELECT @escaped_command_string = @escaped_command_string + @curr_char
    SELECT @curr_char_index = @curr_char_index + 1
  END
  RETURN @escaped_command_string
END

下面是消除了命令 shell 插入漏洞之后的存储过程: 
    CREATE PROCEDURE usp_DoFileCopy @filename varchar(255) AS
    DECLARE @cmd varchar (8000)
    SET @cmd = 'copy srcshare' 
      + dbo.fn_escapecmdshellstring (@filename) 
      + ' destshare'
    EXEC master.dbo.xp_cmdshell @cmd

3)允许执行动态构建的查询的命令

EXEC() sp_executesql。转义对数据库引擎可能具有特殊意义的字符序列。在 T-SQL 中,注入式攻击中最常用的两个字符串为单引号字符 (') 和注释字符序列 (--) SQL 注入式攻击的风险并不是避免动态 SQL 的唯一理由。任何通过这些命令动态执行的查询都将在当前用户的安全上下文中运行,而不是在该存储过程所有者的上下文中运行。这就意味着,使用动态 SQL 可能会强制您授予用户直接访问基表的权限。以下面的存储过程为例:

CREATE PROC dbo.usp_RetrieveMyUserInfo
    AS
    SELECT * FROM UserInfo WHERE UserName = USER_NAME()

此过程会限制当前用户,使其无法查看其他任何用户的数据。但是,如果此过程中的 SELECT 语句是通过动态 EXEC() 或通过 sp_executesql 执行的,您则必须授予用户对 UserInfo 表的直接 SELECT 权限,这是因为这个动态执行的查询是在当前用户的安全上下文中运行的。如果用户能够直接登录服务器,他们则可以使用此权限跳过该存储过程提供的行级安全,查看所有用户的数据。

小结

(1)总而言之,下面的建议将有助于您开发在 SQL Server 中安全运行的 T-SQL 代码:

保护您的开发 SQL Server 的安全,就好像它是一个生产服务器一样。这样有助于确保您开发安全的代码,还可以帮助您定义应用程序正常运行所需的最低权限集。
进行 T-SQL 开发和测试时请使用具有最低权限的 SQL Server 帐户。不要使用 sysadmin dbo 帐户。
对于允许 T-SQL 执行任意外部代码的存储过程,要非常注意,如 sp_OACreate xp_cmdshell。如果必须使用这些扩展,则一定要考虑它们独特的安全隐患。
请遵照保护 T-SQL 开发的最佳方法,其中包括:将用户提供的数据以显式参数进行传递、编写可避免 SQL 注入式攻击的代码、避免使用不必要的动态 SQL、授予访问存储过程的权限而不要授予直接访问基表的权限。
安全的 T-SQL 才能构成安全的应用程序。利用下面的资源可以确保您的服务器进行了安全配置,并确保您拥有一个安全的数据库客户端应用程序。
 

(2)去掉当前用户以下权限:

名称缺省最低角色
xp_cmdshell
sysadmin 固定服务器角色的成员
  
Sp_OACreatesysadmin 固定服务器角色的成员
Sp_OADestroysysadmin 固定服务器角色的成员
Sp_OAGetErrorInfosysadmin 固定服务器角色的成员
Sp_OAGetProperty sysadmin 固定服务器角色的成员
Sp_OAMethodsysadmin 固定服务器角色的成员
Sp_OASetPropertysysadmin 固定服务器角色的成员
Sp_OAStopsysadmin 固定服务器角色的成员
  
EXEC()用户上下文
sp_executesql用户上下文
  
xp_readmail
sysadmin 固定服务器角色成员 以及master数据库中的db_owner固定数据库角色成员
  
Xp_regaddmultistring  
Xp_regdeletekey  
Xp_regdeletevalue  
Xp_regenumvalues  
Xp_regreadPublic数据库角色成员
Xp_regremovemultistring  
Xp_regwrite 
  
sp_makewebtask  

--脚本如下:
USE MASTER
GO

DECLARE @curr_user VARCHAR(128), @access_ctrl_sql VARCHAR(128)

SET @curr_user = USER_NAME()

-- 1. xp_cmdshell
SET @access_ctrl_sql = 'DENY EXECUTE ON xp_cmdshell TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 2. Sp_OACreate
SET @access_ctrl_sql = 'DENY EXECUTE ON Sp_OACreate TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 3. Sp_OADestroy
SET @access_ctrl_sql = 'DENY EXECUTE ON Sp_OADestroy TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 4. Sp_OAGetErrorInfo
SET @access_ctrl_sql = 'DENY EXECUTE ON Sp_OAGetErrorInfo TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 5. Sp_OAGetProperty
SET @access_ctrl_sql = 'DENY EXECUTE ON Sp_OAGetProperty  TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 6. Sp_OAMethod
SET @access_ctrl_sql = 'DENY EXECUTE ON Sp_OAMethod TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 7. Sp_OASetProperty
SET @access_ctrl_sql = 'DENY EXECUTE ON Sp_OASetProperty TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 8. Sp_OAStop
SET @access_ctrl_sql = 'DENY EXECUTE ON Sp_OAStop TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 9. xp_readmail
SET @access_ctrl_sql = 'DENY EXECUTE ON xp_readmail TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 10. xp_regread
SET @access_ctrl_sql = 'DENY EXECUTE ON xp_regread TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

-- 11. sp_makewebtask
SET @access_ctrl_sql = 'DENY EXECUTE ON sp_makewebtask TO ' + @curr_user
EXEC(@access_ctrl_sql)
IF @@ERROR <> 0
BEGIN
 GOTO ERROR_HANDLE
END

SUCCESS_HANDLE:
BEGIN 
 print '为用户 ' + @CURR_USER + ' 收回重要的存储过程执行权限成功'
 RETURN
END

ERROR_HANDLE:
BEGIN
 print '为用户 ' + @CURR_USER + ' 收回重要的存储过程执行权限失败'
 RETURN
END

GO

[@more@]

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/66009/viewspace-796001/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2009-04-22

  • 博文量
    273
  • 访问量
    2169325