编写安全的 Transact-SQL
2007-11-11 07:08:05 来源:WEB开发网遵照保护 T-SQL 的最佳方法
防御一系列称为“SQL 注入式”的安全漏洞是至关重要的。通常情况下,您会使用多层防护来抵御 SQL 注入式攻击:
? | 执行用户提供输入的验证(例如,强制数据类型和最大字符串长度)。 |
? | 转义对数据库引擎可能具有特殊意义的字符序列。在 T-SQL 中,注入式攻击中最常用的两个字符串为单引号字符 (') 和注释字符序列 (--)。 |
? | 在 T-SQL 语句中,请不要将用户提供的值进行内联。请改为使用预处理语句和参数化。 |
SQL 注入式攻击在其他一些地方有详细的说明,所以在此我就不花大量时间来讨论这个问题的细节了。但是要强调一点,SQL 注入式问题并不只限于在应用层构建的 T-SQL 查询。只要执行一个部分由用户提供值构建的 T-SQL 查询,就可能会发生 SQL 注入式问题。这就是说,一个在内部构建查询字符串、并通过 EXEC() 命令或 sp_executesql 存储过程执行该查询的存储过程也可能会受到攻击。请参阅“参考资料”部分获得一些资源链接,这些资源提供了各种 SQL 注入式攻击类型的示例,还提供了一些保护代码免受这些攻击的技巧。
另一个最佳方法是避免针对基表授予权限。对于您希望用户能够执行的查询,您应该将其打包在存储过程中,并只对这些存储过程授予 EXECUTE 权限。如果您按照本指南进行操作,即使用户设法跳过了您的应用程序,直接登录到数据库,他们也无法回避您已经在存储过程中构建的任何数据验证、审核、业务规则或者行级安全限制。
了解具有独特安全考虑事项的 T-SQL 命令
有一些 T-SQL 命令和扩展,它们具有自己独特的安全考虑事项。其中一个是 sp_OACreate 及其相关的系统过程系列(例如 sp_OAMethod、sp_OAProperty 等)。以前,我们曾经研究过一个潜在的安全问题,通过授予应用程序登录直接访问这些过程的权限,会带来该安全问题。为了避免此问题的发生,请绝对不要编写直接调用 sp_OA 过程的应用程序代码,而要将对这些过程的所有引用都打包在您自己的 T-SQL 存储过程中,并只授予访问这些包装存储过程的权限。另外,请不要允许应用程序代码将 COM 对象或方法的名称作为可由包装过程无条件调用的字符串进行传递。
另一个具有独特安全风险集的内置 sql server(WINDOWS平台上强大的数据库平台) 扩展为 xp_cmdshell。这个系统存储过程可以运行任何可执行文件或系统命令。由于一些很显然的原因,xp_cmdshell 上的 EXEC 权限默认情况下仅为 sysadmin 用户,必须显示地为其他用户授予该权限。如果您需要应用程序在 sql server(WINDOWS平台上强大的数据库平台) 上运行某个特定的命令或实用程序,则请注意,不要在应用程序中构建一个 xp_cmdshell 直接访问的相关内容。这样的风险与直接访问 sp_OACreate 的风险相似。一旦为某个帐户授予了 xp_cmdshell 的 EXEC 权限,该帐户不但能够执行您希望其访问的特定命令,而且能够执行成百上千个操作系统命令和其他可执行文件。与 sp_OACreate 相似,始终将 xp_cmdshell 调用打包在另一个存储过程中,避免直接在 xp_cmdshell 上授予 EXECUTE 权限。
您还应该避免将任何用户提供的字符串参数或者应用程序提供的字符串参数与将要通过 xp_cmdshell 执行的命令进行串联。如果无法达到上述要求,则必须了解,有一个专门针对 xp_cmdshell 的潜在的代码注入式攻击(至少在 sql server(WINDOWS平台上强大的数据库平台) 中)。以下面的存储过程为例:
CREATE PROCEDURE usp_DoFileCopy @filename varchar(255) ASDECLARE @cmd varchar (8000)SET @cmd = 'copy \\src\share\' + @filename + ' \\dest\share\'EXEC master.dbo.xp_cmdshell @cmdGOGRANT EXEC ON usp_DoFileCopy TO myapplogin
通过将 xp_cmdshell 调用打包在您自己的存储过程中并只针对该 usp_DoFileCopy 存储过程授予 EXEC 权限,您已经阻止了用户直接调用 xp_cmdshell 以执行任意命令。然而,以下面的 shell 命令插入为例:
EXEC usp_DoFileCopy @filename = ' & del /S /Q \\dest\share\ & '
使用这个 @filename 参数,将要执行的字符串为 copy \\src\share\ & del /S /Q \\dest\share\ & \\dest\share。和号 (&) 被操作系统命令解释器处理为命令分隔符,因此该字符串将被 CMD.EXE 视为三个互不相关的命令。其中第二个命令 (del /S /Q \\dest\share\) 将尝试删除 \\dest\share 中的所有文件。通过利用该存储过程中某个 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) ASBEGINDECLARE @escaped_command_string nvarchar(4000),@curr_char nvarchar(1),@curr_char_index intSELECT @escaped_command_string = N',@curr_char = N',@curr_char_index = 1WHILE @curr_char_index <= LEN (@command_string)BEGINSELECT @curr_char = SUBSTRING (@command_string, @curr_char_index, 1)IF @curr_char IN ('%', '<', '>', '|', '&', '(', ')', '^', '"')BEGINSELECT @escaped_command_string = @escaped_command_string + N'^'ENDSELECT @escaped_command_string = @escaped_command_string + @curr_charSELECT @curr_char_index = @curr_char_index + 1ENDRETURN @escaped_command_stringEND
下面是消除了命令 shell 插入漏洞之后的存储过程:
CREATE PROCEDURE usp_DoFileCopy @filename varchar(255) ASDECLARE @cmd varchar (8000)SET @cmd = 'copy \\src\share\'+ dbo.fn_escapecmdshellstring (@filename)+ ' \\dest\share\'EXEC master.dbo.xp_cmdshell @cmd
第三个具有独特安全考虑事项的 T-SQL 命令集为那些允许执行动态构建的查询的命令:EXEC() 和 sp_executesql。SQL 注入式攻击的风险并不是避免动态 SQL 的唯一理由。任何通过这些命令动态执行的查询都将在当前用户的安全上下文中运行,而不是在该存储过程所有者的上下文中运行。这就意味着,使用动态 SQL 可能会强制您授予用户直接访问基表的权限。以下面的存储过程为例:
CREATE PROC dbo.usp_RetrieveMyUserInfo ASSELECT * FROM UserInfo WHERE UserName = USER_NAME()
此过程会限制当前用户,使其无法查看其他任何用户的数据。但是,如果此过程中的 SELECT 语句是通过动态 EXEC() 或通过 sp_executesql 执行的,您则必须授予用户对 UserInfo 表的直接 SELECT 权限,这是因为这个动态执行的查询是在当前用户的安全上下文中运行的。如果用户能够直接登录服务器,他们则可以使用此权限跳过该存储过程提供的行级安全,查看所有用户的数据。
小结
总而言之,下面的建议将有助于您开发在 sql server(WINDOWS平台上强大的数据库平台) 中安全运行的 T-SQL 代码:
? | 保护您的开发 sql server(WINDOWS平台上强大的数据库平台) 的安全,就好像它是一个生产服务器一样。这样有助于确保您开发安全的代码,还可以帮助您定义应用程序正常运行所需的最低权限集。 |
? | 进行 T-SQL 开发和测试时请使用具有最低权限的 sql server(WINDOWS平台上强大的数据库平台) 帐户。不要使用 sysadmin 或 dbo 帐户。 |
? | 对于允许 T-SQL 执行任意外部代码的存储过程,要非常注意,如 sp_OACreate 和 xp_cmdshell。如果必须使用这些扩展,则一定要考虑它们独特的安全隐患。 |
? | 请遵照保护 T-SQL 开发的最佳方法,其中包括:将用户提供的数据以显式参数进行传递、编写可避免 SQL 注入式攻击的代码、避免使用不必要的动态 SQL、授予访问存储过程的权限而不要授予直接访问基表的权限。 |
? | 安全的 T-SQL 才能构成安全的应用程序。利用下面的资源可以确保您的服务器进行了安全配置,并确保您拥有一个安全的数据库客户端应用程序。 |
参考资料
asp" target="_blank">sql server(WINDOWS平台上强大的数据库平台) Security Resource Page
aspx?pull=/library/en-us/dnnetsec/html/secnetlpMSDN.asp" target="_blank">Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication
sql server(WINDOWS平台上强大的数据库平台) 2000 SP3 Security Features and Best Practices: Secure Multi-tier Deployment
更多精彩
赞助商链接