简介 本白皮书面向的对象是 Microsoft SQL Server 管理员和开发人员,主要是介绍 SQL Server 2000 Service Pack 3 (SP3) 的安全功能。本文讨论了安全方面的一些最佳做法,给出了详细的建议信息,并提供了一些源代码示例。最后,列出了安全最佳做法检查表。本白皮书的重点是 SQL Server 引擎。有关复制、分析服务或数据转换服务的详细讨论,请参阅 http://go.microsoft.com/fwlink/?LinkId=15402。 前提 SQL Server 2000 安全是基于 Microsoft Windows NT 4.0® 和 Windows 2000 安全模型实现的,因此,阅读本白皮书的前提是读者对 Windows NT 4.0 和 Windows 2000 安全有一个基本的了解。另外一个前提就是,读者理解域、全局组、本地组和用户帐户应用于 Windows NT 4.0 安全上下文时的概念,以及 Windows 2000 中 Microsoft Active Directory ®的概念。 对于那些对代码示例感兴趣的读者,学习 Microsoft Visual Basic® 和结构化查询语言 (SQL) 有助于增强理解。此外,有使用 SQL 分布式管理对象 (SQL-DMO) 的经验对理解本白皮书中的内容也大有好处。 但是,即便是那些对 Windows NT 4.0、Windows 2000 或 SQL Server 知之甚少的读者,通过阅读本文,也将对使用这些产品时的安全性有一个大概的了解。 SQL Server 2000 安全模型 SQL Server 2000 安全模型是基于 Windows 安全模型实现的。有关 Windows 安全最佳做法的详细讨论,请参阅 http://go.microsoft.com/fwlink/?LinkId=15392。 应该按图 1 所示保护 SQL Server 2000 的安全。
图" 1:Windows 用户和组为 SQL Server 管理员提供了强大且灵活的安全模型
上图中的步骤可以总结为如下几点: 1. 将每个域中的用户指派到 Windows 全局组。 2. 将各个域中的 Windows 全局组放入 Windows 本地组。 3. 授予 Windows 本地组登录 SQL Server 2000 的权限。 4. 授予 Windows 本地组访问适当数据库的权限。此 Windows 本地组可能与步骤 3 中被授予登录权限的本地组不同。因此,通常重复步骤 1 和 2 来按需要的访问权限组织用户。 5. 为 Windows 本地组分配对特定数据库对象的访问权限。 另一种实现安全的途径是基于角色的使用,通常通过如图 2 所示的方式来实现。
图" 2:基于角色的安全是 SQL Server 2000 中的另一个安全选项
当使用角色来分配对象权限时,仍然需要使用建议的方法为各个用户授予对服务器和数据库的访问权限。 步骤 1 到步骤 4 与图 1 中基本相同,所不同的只是可能不必创建多个 Windows 全局组和本地组。同时,它还对 Windows 2000 通用组提供完全支持。 步骤 5:将各个 Windows 帐户和 Windows 组分配给某个角色。 步骤 6:为角色分配对象访问权限。 使用角色,通过在 SQL Server 2000 内组织用户而减少了在 Windows 内组织用户的需要。 身份验证模式 SQL Server 2000 提供两种身份验证模式来保护对服务器访问的安全:Windows 身份验证模式和混合模式。 Windows 身份验证模式 Windows 身份验证模式是 SQL Server 2000 中的默认身份验证模式。在 Windows 身份验证模式下,SQL Server 2000 仅依赖用户的 Windows 身份验证。然后,授予 Windows 用户或组对 SQL Server 的访问权限。使用此模式与服务器建立的连接称为信任连接。 当使用 Windows 身份验证模式时,数据库管理员通过授予用户登录 SQL Server 2000 的权限来允许他们访问运行 SQL Server 的计算机。Windows 安全标识符 (SID) 用于跟踪已经过 Windows 验证的登录。使用 Windows SID,数据库管理员可以直接授予 Windows 用户或组登录权限。 混合模式 在混合模式下,可以使用 Windows 身份验证或 SQL Server 身份验证对用户进行验证。SQL Server 负责维护经过 SQL Server 身份验证的用户的用户名和密码对。 如果客户端和服务器能够使用 NTLM 或 Kerberos 登录身份验证协议,则以混合模式连接的 SQL Server 就像使用 Windows 身份验证模式一样,也依赖 Windows 来验证用户身份。如果客户端无法使用标准 Windows 登录,则 SQL Server 要求提供用户名和密码对,并将其与存储在系统表中的用户名和密码对进行比较。依赖用户名和密码对的连接称为非信任连接或 SQL 连接。 在内部使用安全标识号 SQL Server 使用 SID 跟踪信任的登录。可以直接对 Windows 用户和组授予对数据库或特定数据库对象的访问权限。例如,Jane 同时是 Windows 中 SALES 和 MARKETING 组的成员。SALES 组被授予了登录 SQL Server 以及访问 pubs 数据库的权限。管理员可以通过 Jane 的 Windows 名称 REDMOND\Jane 授予其访问 authors 表的权限。Windows 帐户必须通过域和用户名来引用。在这种情况下,Jane 的 SID 将存储在 pubs 数据库的系统表中。SQL Server 2000 不支持用户主体名 (UPN)。例如,如果 Windows 登录包含域 SALES 和用户名 SOMEONE,那么登录到 SQL Server 时应使用 SALES\SOMEONE,而不能使用 Windows 2000 Active Directory 所支持的 SOMEONE@MYCOMPANY.COM 形式的登录。 角色 角色的使用与 Windows 组的使用很相似。通过角色,可以将用户集中到一个单元中,然后对这个单元应用权限。对角色授予、拒绝或吊销权限时,将对其中的所有成员生效。可以用角色来代表一个组织中某一类工作人员所执行的某项工作,然后对该角色授予权限。当工作人员执行该项工作时,便成为该角色的成员;而当不再执行该项工作时,便不再是该角色的成员。这样,就不必在用户接受或离开某项工作时,反复地授予、拒绝或吊销每个用户的权限。 角色的功能之所以如此强大,其中涉及到了许多关键的概念。首先,除固定的服务器角色外,其他角色都是在数据库内部实现的。这意味着数据库管理员无需依赖 Windows 管理员来组织用户。第二,角色可以嵌套。嵌套的深度没有限制,但不允许循环嵌套。第三,数据库用户可以同时是多个角色的成员。 因为角色的这些特性,使得数据库管理员可以安排权限的层次结构,以反映使用数据库的组织的管理结构。例如,财务部门可能包含分别负责应付帐款和应收帐款的不同组。数据库管理员可以分别为 APEmployees 和 AREmployees 创建不同的数据库角色,并只对每个角色分配完成相应工作的雇员所需的权限。然后,数据库管理员可以创建一个 FinManagers 角色,并使之包含这两个限制较多的角色(APEmployees 和 AREmployees)。这样,FinManagers 将具有他们的直接下属雇员的所有权限。当某个负责应付帐款的雇员被提升为管理人员时,数据库管理员只需要将其添加到 FinManagers 角色中即可。 public 角色 public 角色在每个数据库(包括系统数据库 master、msdb、tempdb 和 model)中都存在。public 角色提供数据库中用户的默认权限,不能删除。其功能相当于 Windows NT 4.0 环境中的 Everyone 组。每个数据库用户都自动是此角色的成员,因此,无法在此角色中添加或删除用户。 预定义角色 SQL Server 2000 包括几个预定义的角色。这些角色具有预定义的、不能授予其他用户帐户的内在权限。有两种类型的预定义角色:固定服务器角色和固定数据库角色。 固定服务器角色 固定服务器角色的作用域在服务器范围内。它们存在于数据库之外。固定服务器角色的每个成员都能够向该角色中添加其他登录。 注意 Windows BUILTIN\Administrators 组(本地管理员组)的所有成员都默认是 sysadmin 角色的成员。 表 1列出了 SQL Server 2000 中存在的固定服务器角色。
表" 1:SQL Server 2000 固定服务器角色
要将用户添加到固定服务器角色中,请使用下列 Transact-SQL 语句: /* Add Bob to the sysadmin server role */ exec sp_addsrvrolemember "REDMOND\Bob", "sysadmin" 可以将 Windows 用户和组添加到服务器角色中。下列代码显示了如何使用 SQL 分布式管理对象 (DMO) 集合将用户添加到服务器角色中: ' Declare variables Dim oServer As SQLDMO.SQLServer ' Create a server object and connect Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Add Bob to the sysadmin server role oServer.ServerRoles("sysadmin").AddMember ("REDMOND\Bob") 有关如何使用固定服务器角色的详细信息,请参阅 SQL Server 联机丛书。 固定数据库角色 固定数据库角色在数据库级别定义,并在每个数据库中都存在。db_owner 和 db_security 管理员角色的成员可以管理固定数据库角色的成员身份;但是,只有 db_owner 角色可以将其他用户添加到 db_owner 固定数据库角色中。 表 2 列出了 SQL Server 2000 中存在的固定数据库角色。
表" 2:SQL Server 2000 固定数据库角色
有关如何使用固定数据库角色的详细信息,请参阅 SQL Server 联机丛书。 用户定义的角色 当一组用户执行 SQL Server 2000 中的一组指定的活动时,通过用户定义的角色可以轻松地管理数据库中的权限。在没有合适的 Windows 组,或数据库管理员无权管理 Windows 用户帐户的情况下,用户定义的角色为数据库管理员提供了与 Windows 组同等的灵活性。 用户定义的角色只适用于数据库级别,并且只对创建时所在的数据库起作用。 应用程序角色 应用程序角色使得数据库管理员可以将数据访问权限仅授予使用特定应用程序的那些用户。 下面说明其工作过程。用户通过应用程序连接到数据库。然后,应用程序通过执行 sp_setapprole 存储过程向 SQL Server 证明其身份。该存储过程带有两个参数:应用程序角色名和密码。(只有应用程序知道应用程序角色密码。)如果应用程序角色名和密码有效,将激活应用程序角色。此时,当前分配给该用户的所有权限都被除去,并采用应用程序角色的安全上下文。由于只有应用程序(而非用户)知道应用程序角色的密码,因此只有应用程序可以激活此角色,并访问该角色有权访问的对象。 应用程序角色一旦激活,便不能被停用。用户重新获得其原始安全上下文的唯一方法是断开连接,然后再重新连接到 SQL Server。 应用程序角色在两种身份验证模式下都可以工作,并且不包含成员。用户无法与应用程序角色关联,因为应用程序使用 sp_setapprole 存储过程请求应用程序角色的安全上下文。 与用户定义的角色类似,应用程序角色也只存在于数据库内部。如果应用程序角色试图访问其他数据库,将只授予它该数据库中 guest 帐户的特权。如果未明确授予 guest 帐户访问数据的权限,或该帐户不存在,应用程序角色将无法访问其中的对象。 使用应用程序角色的另一个关键概念是在 SQL Server 2000 内对运行应用程序的用户进行审核。也就是说,应用程序角色提供检查数据库对象权限的安全上下文,但实际用户的身份并不会丢失。 下面是使用应用程序角色的一个示例。如果 Jane 是 ACCOUNTING 组的成员,并且仅允许 ACCOUNTING 组的成员通过记帐软件包访问 SQL Server 中的数据,则需要对记帐软件创建一个应用程序角色。ACCOUNTING 应用程序角色被授予访问数据的权限,但 Windows 组 ACCOUNTING 将被拒绝访问该数据。因此,当 Jane 试图使用 SQL 查询分析器访问数据时,将遭到拒绝;但是如果使用了记帐软件,便可以访问数据。 下面的过程概要说明了应用程序使用应用程序角色的步骤。要使用应用程序角色,请执行下列步骤: 1. 创建应用程序角色。 2. 对该应用程序角色分配权限。 3. 确保最终用户通过应用程序连接到服务器。 4. 确保客户端应用程序激活该应用程序角色。 此过程的前两步与最后两步通常是独立的。下面给出了分别用于 Transact-SQL 和 Microsoft Visual Basic 的两个代码片段。 Transact-SQL 脚本如下所示: /* Create the application role. */ EXEC sp_addapprole "AccAppRole", "ABC" /* Grant permissions to SELECT. */ GRANT SELECT ON authors TO AccAppRole GO 下面是用于激活该角色的代码: /* Activate the role. */ EXEC sp_setapprole "AccAppRole", {ENCRYPT N "ABC"} 可以选择对密码进行加密。当必须通过广域网 (WAN) 传递密码时,对密码进行加密可以确保更高的安全性。 下面是 Visual Basic 代码: ' Declare variables. Dim oServer As SQLDMO.SQLServer Dim oDbRole As SQLDMO.DatabaseRole ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Create the Role object. Set oDbRole = CreateObject("SQLDMO.DatabaseRole") ' Set the appropriate properties. oDbRole.Name = "AccAppRole" oDbRole.AppRole = True oDbRole.Password = "45$#Jxew&fd2$Dw53987" ' Add the Role object to the servers Role collection. oServer.Databases("pubs").DatabaseRoles.Add oDbRole 使用角色: ' Declare variables. Dim oConnection As ADODB.Connection ' Create the connection object and connect. Set oConnection = CreateObject("ADODB.Connection") oConnection.Provider = "sqloledb" oConnection.Open "Server=SERVERNAME;Database=pubs;Trusted_Connection=yes" ' Activate the application role. There is no error handling for this sample. oConnection.Execute "EXEC sp_setapprole 'AccAppRole', {ENCRYPT N '45$#Jxew&fd2$Dw53987'}, 'ODBC'" 必须对 OLE DB 和 ODBC 数据源设置加密样式(最后一个参数)。其他数据源无法明确加密密码。在这些情况下,必须对服务器使用加密的通信协议。有关 SSL 和 IPSec 的讨论,请参阅本白皮书后面的内容。 应用程序角色是在每个会话中实现的。如果应用程序打开了多个会话,并且所有会话都被要求使用同一个角色,则每个会话都必须先激活该角色。 可以通过实现应用程序角色来提供比以往任何时候更细粒度的安全性。例如,客户端应用程序可以在某些连接上使用用户的安全上下文,而在另一些连接上使用应用程序角色。 当使用应用程序角色时,执行 SELECT USER 将返回当前使用的应用程序角色的名称。如果要获得已登录用户的身份,应使用下列 Transact-SQL 语句:SELECT SYSTEM_USER。 注意 使用应用程序角色要求存储密码。请务必使用适当的加密和 ACL。请参阅本白皮书后面的"存储凭据"主题。 保护服务器访问的安全 在 SQL Server 2000 中,两种身份验证模式对服务器访问的控制是不同的。但是,在用户获得对服务器的访问权限之后,两种身份验证模式就完全相同。安装时,SQL Server 2000 安全默认为 Windows 身份验证。 Windows 级 要在 Windows 级保护访问的安全,管理员应该为即将访问 SQL Server、但还没有帐户的每个用户创建一个 Windows 域登录帐户。 在 Windows 域级创建全局组,并使每个全局组具有在组织中执行特定工作职能所需的权限。将 Windows 用户添加到相应的全局组。在运行 SQL Server 2000 的计算机上,创建 Windows 本地组,并使每个本地组具有用户在 SQL Server 上执行各类工作所需的权限。最后,将相应的 Windows 全局组添加到 Windows 本地组。 此过程的目的是将权限和用户组织到相应的组中,以便于集中管理。虽然预备过程看起来可能过于复杂,但强烈建议您这样做。最初投入一定的成本来制定周密的安全规划会产生复合效益,例如,增强系统安全以及简化将来的管理过程。 有关 Windows 级安全的详细讨论,请参阅 http://go.microsoft.com/fwlink/?LinkId=15394。 保护数据库访问的安全 成功的登录并不会自动允许用户访问 SQL Server 2000 上的所有数据库,而必须授予用户访问数据库的权限。 在这一部分,我们不区分非信任用户、Windows 用户和 Windows 组。当提到 Windows 用户或组时,可以是信任域中的用户或全局组,也可以是同一目录树或目录林内的域中的用户或全局组。 在每个数据库内,创建一个用户并将该用户链接到 SQL Server 登录、Windows 用户或 Windows 组。 SQL Server 企业管理器(用于管理 SQL Server 2000 的一个 Microsoft 管理控制台 [MMC] 管理单元)不允许创建没有特定的登录权限的用户。MMC 创建了一个已被授权登录服务器的所有帐户列表,您需要从该列表中进行选择。这同样适用于 SQL-DMO 对象模型。 使用 Transact-SQL,可以授予任何有效的 SQL Server 登录、Windows 用户或 Windows 组访问数据库的权限,而无需考虑 master 数据库的 sysxlogins 表中是否存在特定的登录。 注意 虽然不作为一项技术要求,但是如果您使用信任连接,则强烈建议您在每个数据库中创建与登录名同名的用户名。 下面列举了授予数据库使用权限时需使用的一些 Transact-SQL 语句示例: /* Grant access to Bob. */ exec sp_grantdbaccess 'REDMOND\Bob' /* Grant access to Wendy, referring to her by first name within this database. */ exec sp_grantdbaccess 'REDMOND\WendyH', 'Wendy' 只需进行一处修改即可使该示例适用于非信任客户端。即,不使用域用户名,而是使用 SQL Server 2000 用来验证用户的用户名。 如果使用 SQL-DMO,则通过下列代码可实现同等功能: ' Declare variables. Dim oServer As SQLDMO.SQLServer Dim oUser As SQLDMO.User ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Create the User object. Set oUser = CreateObject("SQLDMO.User") ' Set the appropriate properties. oUser.Name = "Bob" oUser.Login = "REDMOND\Bob" ' Add the User object to the servers Users collection. oServer.Databases("pubs").Users.Add oUser SQL Server 级 在 SQL Server 2000 级,必须对创建的 Windows 本地组授予 SQL Server 登录权限。还可以直接将 SQL Server 的登录权限授予用户,但从管理的角度讲,这只有在最小规模的环境中才实用。可以使用企业管理器授予服务器登录权限,或使用 Visual Basic 或 Transact-SQL 通过编程的方法来实现。 使用 Transact-SQL 的数据库管理员应熟悉联机丛书中列出的那些与安全相关的存储过程:
下列" Transact-SQL 语句授予 SALESLG 本地组登录权限: /* Grant login. */ exec sp_grantlogin 'REDMOND\SALESLG' 或者,可以通过下列 Visual Basic 代码来授予登录权限: ' Declare variables. Dim oServer As SQLDMO.SQLServer Dim oLogin As SQLDMO.Login ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Create the Login object. Set oLogin = CreateObject("SQLDMO.Login") ' Set the appropriate properties. oLogin.Name = "REDMOND\SALESLG" oLogin.Type = SQLDMOLogin_NTGroup ' Add the Login object to the server's Logins collection. oServer.Logins.Add oLogin 要允许用户使用非信任连接访问 SQL Server 2000,必须创建用户帐户。 注意 如果 SQL Server 2000 安装在 Windows 上并被配置为使用混合模式,有能力的客户端仍然能够建立信任连接。 下列 Transact-SQL 脚本创建用于建立非信任连接的登录: /* Add a login. */ exec sp_addlogin 'Bob', '45$#Jxew&fd2$Dw53987', 'pubs' 该语句添加一个名为 Bob 的用户,并将密码设置为 password。默认数据库为 pubs。默认数据库是用户试图登录时要切换到的数据库。用户仍然需要在默认数据库中创建一个用户帐户,上述语句才有效;sp_addlogin 不会在引用的数据库中添加用户帐户。或者,上述功能也可以通过 Visual Basic 来实现: ' Declare variables. Dim oServer As SQLDMO.SQLServer Dim oLogin As SQLDMO.Login ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Create the Login object. Set oLogin = CreateObject("SQLDMO.Login") ' Set the appropriate properties. oLogin.Name = "Bob" oLogin.Type = SQLDMOLogin_Standard oLogin.SetPassword "","45$#Jxew&fd2$Dw53987" ' Add the Login object to the server's Logins collection. oServer.Logins.Add oLogin 保护数据库对象访问的安全 可以对角色和用户授予权限,并分配权限来允许用户执行某些语句和访问某些数据库对象。语句权限限制可以执行诸如 CREATE DATABASE、CREATE TABLE 或 CREATE FUNCTION 等语句的用户。对象权限限制对诸如表、视图、用户定义函数或存储过程等对象的访问。对象权限依赖于所引用的对象。例如,表的对象权限包括 SELECT、INSERT、UPDATE、DELETE 和 REFERENCES 等权限,而存储过程上的对象权限则包括 EXECUTE 权限。 用户定义的数据库角色 在理想的环境中,不一定需要角色。以这样一个环境为例:所有用户需要在 Windows 2000 上以 Windows 身份验证模式运行 SQL Server 2000。数据库管理员可以请求 Windows 管理员将具有特定数据访问要求(或角色)的所有用户放入一个 Windows 组,然后,数据库管理员将所需的权限授予该 Windows 组。但在某些环境中,不可能在 Windows 级或域级管理权限,这时可以使用 SQL Server 角色按权限要求来组织用户。 可以将任何 Windows 用户或组分配给某个角色,然后可以像为数据库用户分配权限一样,为该角色分配对数据库对象的访问权限。 注意 只能在数据库中创建用户定义的角色。固定的服务器角色和固定的数据库角色是预先定义的,不能修改。 可以使用下列 Transact-SQL 代码创建角色: /* Add role for Telephone Operators. */ exec sp_addrole "TelephoneOperators" 或者,可以通过下列 Visual Basic 代码来创建角色: ' Declare variables. Dim oServer As SQLDMO.SQLServer Dim oDbRole As SQLDMO.DatabaseRole ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Create the Database Role object. Set oDbRole = CreateObject("SQLDMO.DatabaseRole") ' Set the appropriate properties. oDbRole.Name = "TelephoneOperators" ' Add the Role object to the servers Role collection. oServer.Databases("pubs").DatabaseRoles.Add oDbRole 创建用户定义的数据库角色之后,可以向该数据库角色中添加用户、组或其他角色。为了提高效率,还可以将角色进行嵌套,但不能循环嵌套。 下面的 Transact-SQL 代码示例向新创建的角色中添加 Windows 用户、Windows 组和数据库角色: /* Add a Windows user to the TelephoneOperators role. */ exec sp_addrolemember "TelephoneOperators", "REDMOND\Bob" /* Add a Windows group to the TelephoneOperators role. */ exec sp_addrolemember "TelephoneOperators", "REDMOND\Sales" /* Add HelpDeskOperators role to TelephoneOperators role. */ exec sp_addrolemember "TelephoneOperators", "HelpDeskOperators" SQL-DMO 中的相应代码如下: ' Declare variables. Dim oServer As SQLDMO.SQLServer ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("MSNZBENTHOM") ' Use with statement for code legibility. With oServer.Databases("pubs").DatabaseRoles("TelephoneOperators") ' Add the Windows user to the TelehoneOperators role collection. .AddMember ("REDMOND\Bob") ' Add the Windows group to the TelehoneOperator's role collection .AddMember ("REDMOND \Sales") ' Add the HelpDeskOperators role to TelehoneOperators role collection. .AddMember ("HelpDeskOperators") End With 权限系统 SQL Server 2000 中的权限系统基于组成 Windows 权限基础的同一附加模型。如果某用户同时是 sales、marketing 和 research 角色的成员(多重组成员身份),则该用户获得的权限是每个角色的权限总和。例如,如果 sales 对某个表具有 SELECT 权限,marketing 具有 INSERT 权限,而 research 具有 UPDATE 权限,则该用户能够执行 SELECT、INSERT 和 UPDATE 操作。但是,如果 Windows 拒绝该用户所属的特定角色拥有特定对象权限(如 SELECT),则该用户也没有该权限。限制最多的权限 (DENY) 优先。 授予或拒绝用户和角色权限 数据库内的权限始终授予数据库用户、角色和 Windows 用户或组,但从不授予 SQL Server 2000 登录。为数据库内的用户或角色设置适当权限的方法有:授予权限、拒绝权限和吊销权限。 DENY(拒绝)权限使得管理员可以拒绝用户或角色对对象或语句的权限。与 Windows 权限一样,DENY 权限优先于其他所有权限。 例如,如果只有部分数据库用户总是随意地更改数据,则删除所有用户的权限是不公平的,因为大部分用户都能够做到认真负责地使用数据。可以新建一个名为 trouble_makers 的角色,然后 DENY 该角色在所有表中执行 INSERT、UPDATE 和 DELETE 操作的权限。将行为不端的用户放入 trouble_makers 角色,而不考虑他们所拥有的其他个人、组或角色权限。 计算与对象关联的权限时,第一步就是检查 DENY 权限。如果权限被拒绝,则停止计算,并且不授予权限。如果不存在 DENY,则下一步是将与对象关联的权限与调用方用户或进程的权限进行比较。在这一步中,可能会出现 GRANT(授予)权限或 REVOKE(吊销)权限。如果权限被授予,则停止计算并授予权限。如果权限被吊销,则删除先前 GRANT 或 DENY 的权限。因此,吊销权限不同于拒绝权限。REVOKE 权限删除先前 GRANT 或 DENY 的权限。而 DENY 权限是禁止访问。因为明确的 DENY 权限优先于其他所有权限,所以即使已被授予访问权限,DENY 权限也将禁止访问。 这一节中的每一种方法都适用于 Visual Basic 示例和 Transact-SQL 示例。下列 Transact-SQL 代码授予 Bob 和 Jane 在 authors 表中执行 SELECT 操作的权限,并授予 Jane 在 titles 表中执行 INSERT 操作的权限。 /* Grant permissions to SELECT. */ GRANT SELECT ON authors TO Bob, [REDMOND\Jane] GO /* Grant permissions to INSERT. */ GRANT INSERT ON titles TO [REDMOND\Jane] GO 上面的示例演示了如何使用 GRANT 语句为显式数据库用户 (Bob) 以及 Windows 用户 (Jane) 授予权限。 下面是上述示例在 Visual Basic 中的形式: ' Declare variables. Dim oServer As SQLDMO.SQLServer ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Grant Jane and Bob permissions to select from the authors table. oServer.Databases("pubs").Tables("authors").Grant SQLDMOPriv_Select, "Bob" oServer.Databases("pubs").Tables("authors").Grant SQLDMOPriv_Select, _ "[REDMOND\Jane] ' Grant Jane permissions to select from the authors table. oServer.Databases("pubs").Tables("authors").Grant SQLDMOPriv_Select, _ "[REDMOND\Jane]" 从上面的示例中可看出,通过完全限定域名为用户授予访问权限与直接对已拥有数据库访问权限的用户授予权限之间几乎没有什么区别。由于这种相似性,下列示例仅演示了对现有数据库用户授予权限的代码。 下列 Transact-SQL 语句演示了如何拒绝用户的 SELECT 权限: /* Deny permissions to SELECT. */ DENY SELECT ON authors TO Bob GO 同样也可以使用 Visual Basic: ' Declare variables. Dim oServer As SQLDMO.SQLServer ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Deny Bob permissions to select from authors table. oServer.Databases("pubs").Tables("authors").Deny SQLDMOPriv_Select, "Bob" 下面的 Transact-SQL 示例演示了如何吊销用户的权限: /* Revoke permissions to SELECT. */ REVOKE SELECT ON authors FROM Bob GO 下面是 Visual Basic 中的代码: ' Declare variables. Dim oServer As SQLDMO.SQLServer ' Create a server object and connect. Set oServer = CreateObject("SQLDMO.SQLServer") oServer.Connect ("SERVERNAME") ' Revoke Bob permissions to select from the authors table. oServer.Databases("pubs").Tables("authors").Revoke SQLDMOPriv_Select, "Bob" 所有权链 当多个数据库对象互相按顺序访问时,这种顺序称为"链"。虽然这样的链不具有独立的存在性,但是当 SQL Server 遍历链中的链接时,对组成链对象的用户权限的计算不同于单独访问各个对象时的计算。这种不同对于安全管理具有重要的含义。 如何检查链中的权限 当通过链访问对象时,SQL Server 首先将其所有者与调用方对象(链中的上一个链接)的所有者进行比较。如果两个对象的所有者相同,则不计算所引用的对象的权限。 所有权链接示例 在下面的图 3 中,July2003 视图的所有者是 Mary。她已将该视图的权限授予 Alex。Alex 对本实例中的数据库对象无其他权限。当 Alex 选择该视图时,会出现什么情况呢? 1. Alex 在 July2003 视图上执行 Select * 语句。SQL Server 检查该视图的权限,确认 Alex 拥有在该视图中进行选择的权限。 2. July 2003 视图需要 SalesXZ 视图中的信息。SQL Server 检查 SalesXZ 视图的所有权。由于它与调用方视图的所有者相同 (Mary),因此不检查它的权限。返回所要求的信息。 3. SalesXZ 视图需要 InvoicesXZ 视图中的信息。SQL Server 检查InvoicesXZ 视图的所有权。由于它与前一个对象的所有者相同,因此不检查它的权限。返回所要求的信息。至此,序列中的所有项目均拥有同一个所有者 (Mary)。这称为"未断开的所有权链"。 4. InvoicesXZ 视图需要 AcctAgeXZ 视图中的信息。SQL Server 检查 AcctAgeXZ 视图的所有权。由于它的所有者是 Sam,与前一个项目的所有者 (Mary) 不同,因此得到有关该视图的完整权限信息。如果 AcctAgeXZ 视图具有允许 Alex 访问的权限,将返回信息。 5. AcctAgeXZ 视图需要 ExpenseXZ 表中的信息。SQL Server 检查 ExpenseXZ 表的所有权。由于它的所有者是 Joe,与前一个项目的所有者 (Sam) 不同,因此得到有关该表的完整权限信息。如果 ExpenseXZ 表具有允许 Alex 访问的权限,将返回信息。 6. 当 July2003 视图尝试从 ProjectionsXZ 表中检索信息时,服务器首先查看数据库 1 和数据库 2 之间是否启用了跨数据库链接。如果启用了,服务器将检查 ProjectionsXZ 表的所有权。由于该表与调用方视图的所有者相同 (Mary),因此不检查它的权限。返回所请求的信息。
图" 3:
所有权链接的意义 使用所有权链接,可以通过在单个对象(例如,一个视图)上设置权限来管理对多个对象(例如,多个表)的访问。在允许跳过权限检查的情况下,使用所有权链接在性能上也略胜一筹。 跨数据库所有权链接 可以将 SQL Server 配置为允许在特定的数据库之间或一个实例中的所有数据库之间建立所有权链接。跨数据库所有权链接默认情况下被禁用。并且,除非确实需要,否则不应启用。 潜在威胁 所有权链接在管理数据库权限时非常有用。但是,它假定对象所有者能够预见到授予对象权限的每个决定的全部后果。在图 3 中,Mary 对 July2003 视图的大部分基础对象拥有所有权。由于她有权使她所拥有的对象供其他任何用户访问,因此 SQL Server 表现出来的行为就好像是:只要 Mary 授予对链中的第一个视图的访问权限,就表明她已有意决定共享该视图所引用的视图和表。在现实生活中,这种假定是站不住脚的。生产环境中使用的数据库比图 3 中的数据库要复杂得多,并且控制对数据库访问的那些权限很少能完美地映射到使用这些数据库的组织的管理结构。 需要了解的重要一点是,具有较高特权的数据库角色的成员能够使用跨数据库所有权链接来访问他们所拥有的数据库外部的数据库中的对象。例如,如果在数据库 A 和数据库 B 之间启用了跨数据库所有权链接,则其中任何一个数据库的 db_owner 固定数据库角色的成员都可以通过欺骗的手段访问另一个数据库。过程很简单:Diane(数据库 A 中的 db_owner 的成员)在数据库 A 中创建一个用户 Stuart。Stuart 已作为数据库 B 中的用户存在。然后,Diane 在数据库 A 中创建一个对象(由 Stuart 所有),该对象调用数据库 B 中由 Stuart 拥有的任何对象。由于调用方和被调用方对象的所有者相同,因此当 Diane 通过她创建的对象访问数据库 B 中的对象时,将不会检查她在该对象上的权限。 注意 所有权链接适用于数据操作语言 (DML) 操作(SELECT、UPDATE、INSERT、DELETE),但不适用于数据定义语言 (DDL) 操作。 |