SQL Server 2005比以前的版本要安全得多。整个安全体系结构已经发生了重大变化,增加了许多新特性。例如,权限更细化,有更多的对象是可确保安全,添加了更复杂的密码,SQL Server登录与Windows登录一样安全,已用新的模式对象代替了对象拥有者,但是本章的重点在别的方面。本章会描述数据层的安全体系结构,而不会覆盖SQL Server的所有可能的安全细节。本章首先介绍SQL Server的安全体系结构。然后概述实现和管理安全性的语句和存储过程。最后,它为客户应用程序提供了几个典型的安全体系结构。
19.1 安全体系结构
在SQL Server上实现安全性并不困难,但是在定义和实现有效的和可管理的安全解决方案前要对它的安全体系结构有很好的理解。让我们首先描述一下基本概念和术语。
19.1.1 身份验证与授权
身份验证(authentication)是标识用户或进程的过程。授权(Authorization)是授予通过身份验证的用户或进程以访问或修改资源的指定权限的过程。
19.1.2 主体
主体(principal)是可以请求对SQL Server资源的访问权限的用户、组和进程。主体有几个共同的特征。每个主体都有自己的安全标识号(SID)。主体可以是主体的集合(比如Windows组或数据库角色)或不可分割的主体(比如本地登录或域登录)。每个主体有一个作用域,作用域基于定义主体的级别(见表19-1)。
在下面几节中将试着通过把它们称为“用户”来合理地想象这些抽象的主体。只要记得这种意义上的“用户”可以代表表19-1中所示的任何主体即可。
表19-1 各个级别的主体
|
Windows级别的主体 |
SQL Server级别的主体 |
数据库级别的主体 |
|
本地登录 |
自带SQL Server登录 |
数据库角色 |
|
域登录 |
与Windows登录或组链接在一起的SQL Server登录 |
应用程序角色 |
|
本地组 |
与非对称密钥链接在一起的SQL Server登录 |
数据库用户 |
|
域组 |
与证书链接在一起的SQL Server登录 |
与Windows用户或组链接在一起的数据库用户 与非对称密钥链接在一起的数据库用户 与证书链接在一起的数据库用户 |
19.1.3 可保护对象
可保护对象(securable)是可以用权限来保证其安全的服务器或数据库对象。根据获得对象的作用域可以把它们划分为3组(见表19-2):
表19-2 根据作用域划分的可保护对象
|
服务器作用域的可保护 对象 |
数据库作用域的可保护 对象 |
模式作用域的可保护 对象 |
|
登录 数据库 端点 |
用户 数据库角色 应用程序角色 模式 证书 服务 程序集 消息类型 路由 远程服务绑定 全文本目录 非对称密钥 对称密钥 契约 |
表 视图 存储过程 函数 类型 同义词 聚集 XML模式集合 队列 |
19.1.4 访问级别
用户在执行数据库对象上的操作之前必须仔细检查4个安全级别,如下面的图19-1所示。
1. 网络/OS访问权限
用户需要对客户计算机、操作系统和服务器所位于的网络具有访问权限。通常,授予这种访问权限的工作由技术支持专家或网络管理员负责。然而,在小规模工作环境中,也可以由DBA或开发人员担任。

图19-1 4个安全级别
2. 服务器访问权限
这是严格属于SQL Server的第一个安全级别。它允许客户端访问服务器。这个安全级别总是由数据库管理员负责。
客户端自身必须通过服务器的身份验证(验证它的身份)后才可以请求其他资源。SQL Server支持用Windows或SQL Server身份验证来验证客户端的身份。
SQL Server身份验证基于SQL Server存储在主数据库中的登录名和口令。客户端必须提供登录名和口令,否则会提示它输入这些内容。
Windows身份验证基于Windows(网络)域或本地登录名。客户端对服务器的连接与它的Windows登录名关联在一起。客户端将不显示输入登录名与口令的提示。而是有个幕后进程根据客户端的Windows登录名和SID来验证它的身份。
Windows身份验证通常被认为更安全和更易维护,一部分原因是由于Microsoft已经在Windows中完成了基础设施工作,另一部分原因是由于Internet上有许多可以读取SQL Server登录口令的工具可用。Windows身份验证对于用户(只需记住一个登录名和口令组合,且只需输入一次以登录到网络)和管理员(可以集中管理所有登录名和口令)来说都比较容易管理。
|
注意: |
|
Microsoft在SQL Server 2005中对SQL Server身份验证作了一些改进。例如,SQL Server实例可以设置为需要安全性更强的口令,以及在指定时间段后要求更新口令。然而,Microsoft仍然建议使用Windows身份验证,它声称SQL Server身份验证只应该应用于遗留应用程序。 |
SQL Server可以用两个身份验证模式安装或配置:
● Windows身份验证模式 允许客户端只用Windows身份验证验证自身的身份。在SQL Server 7.0以前,它称为集成安全性。
● 混合身份验证模式 既支持SQL Server也支持Windows身份验证。有些用户可以用他们的网络账户登录,而其他用户(不一定有Windows账户)可以用他们的SQL Server登录名登录。
|
注意: |
|
SQL Server的早期版本可以用Standard安全/模式安装,这种模式只支持SQL Server身份验证。 |
3. 数据库访问权限
访问一个服务器并不意味着用户自动拥有数据库的访问权限。管理员必须以下列方式之一指定一个数据库登录:
● 在每个用户需要访问的数据库中,创建一个与用户登录名对应的数据库用户(database user)。
● 将数据库配置为把登录名/数据库用户作为数据库角色的成员对待。这样,用户将继承角色中的所有权限。
● 将登录名设置为使用默认账户之一:guest或数据库拥有者(dbo)。
一旦授予了对数据库的访问权限,用户就可以看到所有数据库对象,因为对象定义存储在每个用户具有读访问权限的系统表中。
4. 权限
权限是SQL Server安全性的最后一个级别。要拥有对SQL Server上的可保护对象(资源)的访问权限,主体必须具有在它们上面执行动作的权限。
SQL Server 2005有一个新的对象模型,具有较细粒度的权限(比以前的版本粒度细)和层次结构组织。执行sys.fn_builtin_permissions函数可以看到完整列表(见图19-2)。结果中差不多包含200个单独权限。

图19-2 内置权限的列表
主体可以被授予对包含可保护对象(比如表和视图)的模式、模式和数据库的Select、Update、Insert和Delete权限。这个访问级别意味着用户可以读、写、删除或修改数据。Reference权限允许主体使用外键约束来验证使用对象(表或列)的实体的有效性。Execute权限用于程序化的对象(比如存储过程)。
View Definition将允许主体获得创建服务器和数据库对象的脚本,而Alter权限允许主体编辑(修改、删除或创建)服务器或数据库对象。创建对象的数据库用户将成为它们的拥有者(除非它们也是模式的拥有者)。而Take Ownership权限允许其他用户获取它们。Control包括所有权限(包括包含在Alter和Take Ownership内的权限)和授予对象上其他权限的权限。
Alter Any权限仅用于一组特定类的对象上。例如,Alter Any Database允许用户更改服务器上的所有数据库。
图19-2中的表的键是permission_name+class_descr(应用该权限的对象的类名)的组合。
有些权限包含父权限和字段组合,如covering_permission_name+class_descr就是这样的示例。如果主体(用户)具有对象Database类的Control权限,那么权限也暗指所有(子)权限,比如所有Database类对象的View Definition和Alter权限。执行下面的普通表表达式,就可以看到完整的层次结构:
WITH Perms(class_desc, covering_permission_name, permission_name,
level) AS
(
-- anchor member (for first iteration)
SELECT class_desc, covering_permission_name, permission_name, 0 level
FROM sys.fn_builtin_permissions(default)
WHERE covering_permission_name = ''
UNION ALL
-- recursive member (for later iterations)
SELECT o.class_desc, o.covering_permission_name,
o.permission_name, p.level + 1 level
FROM sys.fn_builtin_permissions(default) o
INNER JOIN Perms p
ON o.covering_permission_name = p.permission_name
and o.class_desc = p.class_desc
)
SELECT s.class_desc, s.permission_name, s.covering_permission_name,
s.level
FROM Perms s
INNER JOIN sys.fn_builtin_permissions(default) o
ON o.permission_name = s.permission_name
and o.class_desc = s.class_desc
ORDER BY s.class_desc, s.level;
BOL中包含dbo.ImplyingPermissions用户自定义函数的源代码,它可以用于显示权限下隐含的权限—。例如,当编译了主数据库中的函数后,可以用它获得可以更改存储过程等较高级别的权限的列表(见图19-3)。

图19-3 隐含权限
此外,代码中还有一个基于parent_class_descr+parent_covering_permission_name的层次结构的实现。这个层次结构可以确保如果您具有对较高层次的对象的权限,就也具有对于它们的子对象的权限。例如,如果具有对Schema的Control权限,就暗示了您具有对于该模式中的其他对象(比如表和视图)的Control权限。
19.1.5 角色
可以逐个地对主体授予权限,或者将主体作为角色的成员授予权限。角色相当于Windows域中的组。
在SQL Server的早期版本中,用户可能只属于一个角色(组)。这种限制导致了一些相当不便于重定义的安全解决方案。现在,一个可以是许多角色的成员。与其管理大组的用户及其权限,不如采用对角色授予权限然后将用户分配给角色的方法。因此,角色可以用来提供有效而复杂的安全模型,以及管理可保护对象(功能和对象)的访问权限。
1. 固定服务器角色
服务器级别的主体可以成为服务器角色的成员以控制服务器作用域中的可保护对象(或较低级别的可保护对象。服务器角色是固定的—— 无法修改授予它们的权限,也无法创建新的服务器角色。服务器角色的集合是
● sysadmin
● securityadmin
● serveradmin
● setupadmin
● processadmin
● diskadmin
● dbcreator
● bulkadmin
在SQL Server的早期版本中,可以用下列存储过程来获得授予角色的权限列表:
exec sp_srvrolepermission 'processadmin'
遗憾的是,SQL Server 2005中不支持这个存储过程。在BOL的“Permissions of Fixed Server Roles ”(固定服务器角色的权限)部分中可以找到授予服务器角色的权限列表。
2. 固定数据库角色
数据库级别的主体可以成为固定数据库角色的成员来管理数据库作用域的可保护对象:
● db_accessadmin
● db_backupoperator
● db_datareader
● db_datawriter
● db_ddladmin
● db_denydatareader
● db_denydatawriter
● db_owner
● db_securityadmin
● public
在BOL上的“Permissions of Fixed Database Roles ”(固定数据库角色的权限)中可以得到赋予这些角色的权限列表。
公有角色比较特殊。每个被授予对数据库的访问权限的用户会自动成为公有角色的成员(并继承授予它的权限)。
3. 自定义数据库角色
可以创建一个数据库角色,并赋予对数据库作用域和模式作用域的可保护对象的访问权限。一个用户可以是0个、1个或多个数据库角色(固定或自定义)的成员。
Microsoft建议当不存在可用来管理权限的Windows组时或者当不具有管理Windows组的权限时可创建数据库角色。数据库角色应该总是存在。因为赋予了适当权限的Windows组或用户可能会因某种原因被删除或使用而导致必须重新赋予各个权限。但如果把它们都赋予了一个角色(权限也用这种方式成组),那么把它们重新赋予这个新用户或组要简单得多。
4. 应用程序角色
有时,你可能需要你的用户仅能通过一个客户应用程序访问数据库。这在向中间件组件中构建业务逻辑时非常常见。如果您的用户(或他们的角色)具有对底层对象的访问权限,那么它们可以使用Management Studio等常规工具来直接访问它们。Microsoft创建了应用程序角色来防止用户直接访问底层表。
应用程序角色(Application role)是在没有成员(主体)的数据库级别上定义的,需要一个口令来激活。当连接字符串指定一个应用程序角色并提供口令时,SQL Server会忽视所有用户特权,只赋予用户指派给应用程序角色的特权。
|
注意: |
|
应用程序角色在执行交叉数据库或交叉服务器操作中有一个严重的限制。它们被设计为数据库级的主体,它们不具有创建它们的数据库以外的显式权限。应用程序角色将获得guest账户所具有的权限(通常并不多)。 |
19.1.6 所有权链
像存储过程、视图及函数等数据库对象可以引用其他数据库对象,比如表、其他存储过程、视图和函数。底层对象也可以引用其他数据库对象。对此,您可以把它想象成一棵树,对象连接方式及其结构均与树的相似,不过SQL Server文档把它称为链(chain)。SQL Server在允许用户访问对象之前,必须估计用户在每个对象上的单独的和连贯的权限(这就是为什么把它们称为链)。这一操作可能非常复杂和耗时,但幸运的是SQL Server使用了一条称为拥有者链的捷径。如果所有组成对象属于的模式与引用它们的对象的模式相同,SQL Server就不需要估计用户访问单个(部分)对象的权限。然而,即使有一个对象不属于顶级对象的模式(即如果链被打断),SQL Server也会估计用户对所有底层对象的访问权限。
在SQL Server 2005中,数据库对象由模式拥有。在SQL Server 2005之前,数据库对象由像dbo这样的拥有者拥有,因此,这些链的名称为拥有者链。
拥有者链的主要目标是简化数据库对象的安全管理。通常只要给予用户访问顶级对象(比如存储过程)的权限就足够了。
19.1.7 交叉数据库拥有者链
数据库对象还可以引用其他数据库中的对象。在这种情况下,拥有者链跨多个数据库,它们被称为交叉数据库拥有者链。默认情况下, SQL Server上没有启用交叉数据库拥有者链。然而,在安装服务器的过程中,可以为服务器上的所有数据库启用它们。可选地,也可以启用特定数据库之间的交叉数据库拥有者链。
|
警告: |
|
交叉数据库拥有者链有潜在的危险,除非必要,否则不应使用它们。例如,假设数据库Asset5中有一个用户John拥有属于dbo模式的vInventory视图的Select权限。这个用户还存在于数据库Finance中,不过并没有给他从表dbo.Transactions中选择数据的权限。如果用户可以修改vInventory视图以读取Finanace.dbo.Transactions中的数据,SQL Server将只验证与所有底层对象的模式匹配的视图的模式有效性,并自动让他可以访问Finance数据库的表中数据,而不检查他的权限。 |
19.1.8 执行环境上下文的切换
我们在前面一些章节中演示了如何使用存储过程、用户自定义函数(除了内联表值UDF)和触发器的Execute As子句,以控制执行环境上下文。基本上,我们可以定义一些过程,以使它们在执行时使用不同的身份验证。
Execute As Caller选项是默认的,这与SQL Server早期版本的行为一致。表明用户需要对过程和它引用的所有对象具有权限。
当调用者不具有对底层对象的权限时,以及当需要那些权限时(例如,当过程动态地汇编一个批处理时,仅依靠对过程的权限和模式兼容性是不够的),Execute As User=‘user’选项是有用的。这个过程将在‘用户’(如果他或她有足够的权限)的环境上下文中执行。
Execute As Self选项会使得使用创建或更改过程的用户名执行该过程。
Execute As Owner选项指定这个过程将被作为对象的拥有者执行,或者,如果没有定义拥有者,就会在模式拥有者的环境上下文中执行。拥有者必须是单独的账户—— 它不能是群组或角色。
Execute As语句(我们在上一节中描述了Execute As子句)基于会话级别修改执行的环境上下文。可以指定不同的用户或登录名来分别扮演数据库或服务器级别的角色。在这种情况下,权限将根据指定用户或登录账户的安全环境上下文进行检查,原始登录名的权限会被忽略。
|
注意: |
|
如果将一个会话设置为扮演数据库用户,则对数据库以外的任何对象的访问都会失败(即便用了分布式查询和Use语句也是如此)。 |
一旦设置完成,直到它被再次设置、连接被删除,或者用户调用Revert语句(向原始登录名返回执行环境上下文)时,会话的环境上下文才会生效。







