SQL Server中的所有权链及其问题
没有多少朋友对所有权链真的理解的。我自己有时候经常回过来看看这些资料,觉得还是很有意思的。下面的内容摘自微软文档,介绍得比较好
简而言之
1. 如果在同一个数据库中,只要两个对象的所有者是一样的,那么他们之间的访问是不检查访问者身份的。例如一个视图和一个表是属于同一个所有者,那么只要用户有访问视图的权限,就等于拥有了访问表的权限,即便在表上面明确拒绝了用户的权限。你可能会奇怪了,我们不是经常讲“拒绝优先”吗?没错,拒绝优先是对的,但事情的关键主要在于这个时候,SQL Server根本就不检查权限了,当然就不存在任何问题。
这个特性可能在规划安全时很有用
2. 如果在不同数据库中,也可以实现与上面同样的所有权链接,此时我们称为“跨数据库所有权链”。因为有安全隐患,所以默认该选项是被禁用的
--以管理员登录
USE MASTER
GO
---创建两个数据库
CREATE DATABASE db1
GO
CREATE DATABASE db2
GO
--在第一个数据库中添加一个表,并添加一点数据
USE db1
GO
CREATE TABLE Table1(ID INT)
GO
INSERT INTO Table1 VALUES(1);
INSERT INTO Table1 VALUES(1);
INSERT INTO Table1 VALUES(1);
INSERT INTO Table1 VALUES(1);
--在第二个数据库中添加一个视图,让他去访问第一个数据库中的表
USE db2
GO
CREATE VIEW db1Table1View
AS
SELECT * FROM db1.dbo.Table1
--因为当前用户是管理员,它会属于sysadmin角色,所以可以访问到。即便没有开启跨数据库所有权链
SELECT * FROM db1Table1View
--创建一个LOGIN1
CREATE LOGIN [LOGIN1] WITH PASSWORD=N'pass@word'
--将该登录映射到db2,成为一个用户
CREATE USER [LOGIN1] FOR LOGIN [LOGIN1];
GO
--使用该用户的身份去访问那个视图
EXECUTE AS USER = 'LOGIN1'
SELECT CURRENT_USER --此时会切换到LOGIN1这个用户
SELECT * FROM db1Table1View --此时会失败,因为该用户不具备对视图的访问权限
--授予用户对视图的SELECT 权限
REVERT --回到之前的身份,因为要做授权
SELECT CURRENT_USER --此时的身份会切换回到chenxizhang所代表的用户,也就是dbo
GRANT SELECT ON [dbo].[db1Table1View] TO [LOGIN1]
--再次切换为LOGIN1身份
EXECUTE AS USER ='LOGIN1';
SELECT CURRENT_USER
SELECT * FROM db1Table1View
--此时出现下面这样的错误,说明当前用户确实试图去访问db1的Table1,但因为不能进行上下文链接,所以还是失败了
/*
消息 916,级别 14,状态 1,第 3 行
服务器主体 "LOGIN1" 无法在当前安全上下文下访问数据库 "db1"。
*/
--切换回chenxizhang身份,启用db1数据库的所有权链接
REVERT
SELECT CURRENT_USER
ALTER DATABASE db1 SET DB_CHAINING ON
ALTER DATABASE db2 SET DB_CHAINING ON
--再次切换为LOGIN1身份
EXECUTE AS USER ='LOGIN1';
SELECT CURRENT_USER
SELECT * FROM db1Table1View
/*
此时仍然出现一个错误。和上面是一样的。既然实现了所有权链接,为什么还是不行呢?
原因是因为在db1中也要存在该用户,即他至少要能访问数据库
*/
REVERT
USE db1
GO
CREATE USER LOGIN1 FOR LOGIN [LOGIN1]
GO
USE db2
GO
--再次切换为LOGIN1身份
EXECUTE AS USER ='LOGIN1';
SELECT CURRENT_USER
SELECT * FROM db1Table1View
此时就可以了
http://technet.microsoft.com/zh-cn/library/ms188676.aspx
所有权链
当多个数据库对象按顺序互相访问时,该序列便称为“链”。尽管这样的链不会单独存在,但是当 SQL Server 遍历链中的链接时,SQL Server 评估对构成对象的权限时的方式与单独访问对象时不同。这些差异对管理安全性具有重要的影响。
所有权链接通过设置对某个对象(如视图)的权限允许管理对多个对象(如多个表)的访问。所有权链接在允许跳过权限检查的方案中对性能也有少许提高。
如何在链中检查权限
通过链访问对象时,SQL Server 首先将对象的所有者与调用对象的所有者进行比较。调用对象指链中的上一个链接。如果两个对象的所有者相同,则不评估对被引用对象的权限。
所有权链接的示例
在下图中,July2003 视图由 Mary 所拥有。她已经授予 Alex 对该视图的权限。他对此实例中的数据库对象不具有任何其他权限。当 Alex 选择该视图时,会出现什么情况?
- Alex 对 July2003 视图执行 SELECT *。SQL Server 检查对该视图的权限并确认 Alex 具有对该视图执行选择的权限。
- July2003 视图需要 SalesXZ 视图中的信息。SQL Server 检查 SalesXZ 视图的所有权。因为此视图与调用它的视图具有相同的所有者 (Mary),所以将不检查对 SalesXZ 的权限。返回必需的信息。
- SalesXZ 视图需要 InvoicesXZ 视图中的信息。SQL Server 检查 InvoicesXZ 视图的所有权。因为此视图与上一个对象具有相同的所有者,所以将不检查对 InvoicesXZ 的权限。返回必需的信息。到目前为止,序列中的所有项都有一个相同的所有者 (Mary)。这称为“连续所有权链”。
- InvoicesXZ 视图需要 AcctAgeXZ 视图中的信息。SQL Server 检查 AcctAgeXZ 视图的所有权。因为此视图的所有者与上一个对象的所有者不同(是 Sam,而不是 Mary),所以将检索有关此视图权限的完整信息。如果 AcctAgeXZ 视图具有允许 Alex 访问的权限,将返回所需的信息。
- AcctAgeXZ 视图需要 ExpenseXZ 表中的信息。SQL Server 检查 ExpenseXZ 表的所有权。因为此表的所有者与上一个对象的所有者不同(是 Joe,而不是 Sam),所以将检索有关此表权限的完整信息。如果 ExpenseXZ 表具有允许 Alex 访问的权限,将返回所需的信息。
- 当 July2003 视图试图从 ProjectionsXZ 表中检索信息时,服务器首先检查 Database 1 和 Database 2 之间是否启用了跨数据库链接。如果已经启用跨数据库链接,服务器将检查 ProjectionsXZ 表的所有权。因为此表与调用视图具有相同的所有者 (Mary),所以将不检查对此表的权限,并且将返回所请求的信息。
跨数据库所有权链接
可以对 SQL Server 进行配置,以允许在单个 SQL Server 实例中的特定数据库之间或所有数据库之间建立所有权链接。默认情况下,跨数据库所有权链接是禁用的,除非由于特殊情况而需要,否则不应该启用它。
潜在威胁
所有权链接在管理对数据库的权限时非常有用,但它假设对象的所有者能够预测到授予对某个安全对象的权限时做出的每个决定的所有后果。在上图中,Mary 拥有 July 2003 视图的大多数基础对象。因为 Mary 具有允许其他用户访问她所拥有的对象的权力,所以 SQL Server 会认为只要 Mary 授予对访问链中第一个视图的权限,即表明她已明确决定共享该视图所引用的视图和表。在现实生活中,这可能不是一个有效的假设。生产数据库比图中所示的数据库要复杂得多,并且控制对它们进行访问的权限几乎不会完全映射到使用它们的组织的管理结构中。
您应该了解,高特权数据库角色的成员可以使用跨数据库所有权链接来访问其自身数据库之外的数据库中的对象。例如,如果在数据库 A 和数据库 B 之间启用了跨数据库所有权链接,则任一数据库的 db_owner 固定数据库角色的成员都可以访问另一数据库。过程很简单:Diane(数据库 A 中db_owner 角色的成员)在数据库 A 中创建了用户 Stuart。Stuart 已经作为用户存在于数据库 B 中。然后 Diane 在数据库 A 中创建一个对象(由Stuart 所拥有),该对象调用数据库 B 中 Stuart 所拥有的任何对象。因为调用对象和被调用对象的所有者相同,所以当 Diane 通过她创建的对象访问数据库 B 中的对象时,不会检查她对该对象的权限。
如何启用跨数据库的所有权链
使用 cross db ownership chaining 选项可以为 Microsoft SQL Server 实例配置跨数据库所有权链接。
此服务器选项使您能够在数据库级别控制跨数据库所有权链接,或者允许在所有数据库中启用跨数据库所有权链接:
- 如果实例的 cross db ownership chaining 关闭(设置为 0),将禁用所有数据库的跨数据库所有权链接。
- 如果实例的 cross db ownership chaining 打开(设置为 1),将启用所有数据库的跨数据库所有权链接。
- 可以使用 ALTER DATABASE 语句的 SET 子句为各个数据库设置跨数据库所有权链接。如果正在创建新的数据库,则可以使用 CREATE DATABASE 语句设置新数据库的跨数据库所有权链接选项。
建议不要将 cross db ownership chaining 设置为 1,除非 SQL Server 实例所驻留的所有数据库都必须参与跨数据库所有权链接,并且您了解此设置隐含的安全问题。有关详细信息,请参阅所有权链。
在打开或关闭跨数据库所有权链接之前,请注意下列事项:
- 只有 sysadmin 固定服务器角色成员能够打开或关闭跨数据库所有权链接。
- 关闭生产服务器的跨数据库所有权链接之前,应全面测试所有应用程序(包括第三方应用程序)以确保更改不会影响应用程序功能。
- 如果使用 sp_configure 指定 RECONFIGURE,则在服务器运行时可以更改 cross db ownership chaining 选项。
- 如果有数据库需要跨数据库所有权链接,建议使用 sp_configure 为实例关闭 cross db ownership chaining 选项;然后使用 ALTER DATABASE 语句打开需要此功能的各个数据库的跨数据库所有权链接。