SQLServer中的所有权链是安全还是风险
SQLServer中的所有权链是安全还是风险
--王成辉翻译整理,转贴请注明出自微软BI开拓者
www.windbi.com--
原帖地址问题我曾听说过SQLServer里的所有权链,但我不懂它是什么、它是如何运作的。我想知道它是安全还是风险,如果安全,我怎样使用它。如果是风险,我想知道如何避免它。解决方法所有权链在SQLServer里安全的,不是风险。所有的对象如表和视图都有所有者。在SQLServer2005以及以后的版本里,所有者可以间接来自于对象所属的架构的所有者。让我们来详细的看看。每个对象都包含在一个架构里。SQLServer2005和SQLServer2008里的架构用来把一组对象放进逻辑容器中。例如,对一个特定的应用程序而言,在公司内可能有2类用户,一些来自市场而另外一些来自人力资源。一些对象如针对员工的表,逻辑上适合放在与人力资源类型对象相关的容器里。其他对象适合放在与市场相关对象的容器里,如记录广告运营的表。通过使用架构,可以根据目的来分组对象。作为一个例子,我们可以创建2个这样的架构:CREATE SCHEMA Marketing; GO
CREATE SCHEMA HumanResources; GO |
架构必须有所有者。如果当架构创建的时候没有指定所有者(使用AUTHORIZATION关键字来执行所有者),那么创建架构的用户就是所有者。我们可以使用下面的查询来查看数据库里的架构和它们的所有者:SELECT [name] AS [schema] , [schema_id] , USER_NAME(principal_id) [Owner] FROM sys.schemas; |
这里是数据库AdventureWorks数据库的输出结果:
在SQLServer2005/2008中,当创建一个对象的时候,不必指定所有者。SQLServer将假定对象的所有者就是对象所属架构的所有者。例如,在下面的对象创建语句里,没有指定所有者。因此,那些对象的所有者相当于那些对象所属架构的所有者:CREATE TABLE HumanResources.TestTable ( TableValue INT ); GO
CREATE PROC Marketing.QueryTestTable AS BEGIN SELECT TableValue FROM HumanResources.TestTable; END GO |
第一个对象,一个叫TestTable的表,创建在了架构HumanResources里。第二个对象,一个叫QueryTestTable的存储过程,创建在了架构Marketing里。由于没有其他的T-SQL命令来指定其他对象的所有者,SQLServer在考虑所有权链时将使用各自架构的所有者作为对象的所有者。对象可以通过使用ALTER AUTHORIZATION来明确指定所有者,如这里显示的(CREATE USER语句创建了一个合法用户来作为创建的表的所有者):CREATE USER TestUser WITHOUT LOGIN; GO
CREATE TABLE Marketing.OwnedTable ( TableValue INT ); GO
ALTER AUTHORIZATION ON Marketing.OwnedTable TO TestUser; GO |
我们可以通过查询sys.objects和sys.schemas来得到对象、对象所属的架构,以及对象的有效所有者。如果没有明确指定对象所有者,那么sys.objects的principal_id列将为NULL。通过使用COALESCE,我们可以通过先查看sys.objects的principal_id再查看sys.schemas的principal_id来实际决定所有者。SELECT so.[name] AS [Object] , sch.[name] AS [Schema] , USER_NAME(COALESCE(so.[principal_id], sch.[principal_id])) AS [Owner] , type_desc AS [ObjectType] FROM sys.objects so JOIN sys.schemas sch ON so.[schema_id] = sch.[schema_id] WHERE [type] IN ('U', 'P'); |
这里是AdventureWorks数据库里的头几条数据:
一旦我们理解了一个对象的有效所有者是谁,我们就可以来看看所有权链了。当满足下列条件时就会发生所有权链:- 一个对象引用了另一个对象,如存储过程引用了表
- 两个对象都有相同的所有者
在这样的情形下,一个用户仅需有第一个对象的权限。例如,用早先的那个存储过程Marketing.QueryTestTable来说,它查询了表HumanResource.TestTable。如果两个对象的所有者是相同的,那么一个所有权链就形成了。当一个所有权链形成的时候,SQLServer将只检查第一个对象的权限。因为所有者是相同的,它就假定引用是有意的,并且不会检查引用对象的权限。因此,在这个例子中,如果一个用户有权限去执行Marketing.QueryTestTable,SQLServer将允许查询表HumanResource.TestTable,只要这个查询是通过这个存储过程执行的。
例如,如果我们要控制对那个表的访问以便只能通过存储过程来进行的话,这个例子用T-SQL创建一个角色并分配给角色需要的权限:
CREATE ROLE GrantPermissions; GO
GRANT EXECUTE ON Marketing.QueryTestTable TO GrantPermissions; GO |
通过所有权链的使用,我们可以强迫使用存储过程来访问。这是有利的,比如我们要控制怎样让表里的数据插入、更新或删除。一个好的例子是应用程序一次删除一行数据。明确地给定了一个用户对表的访问权限,那个用户可能因为忘记使用where语句而意外的删除表的所有数据。解决方法就是创建一个存储过程,让它删除基于传入参数的特定的行。存储过程仅允许删除一行。这样,终端用户就不能意外的删除所有的记录了,因为用户没有针对表的权限。用户会试着删除,但他会得到一个访问被拒绝的错误。然而,用户可以执行存储过程,但这样做就仅限于存储过程所影响的范围内了。这就是所有权链的好处。下一篇文章将在本文的基础上,讲解跨数据库所有权链。

拓狼 最后编辑于 2009-07-02 17:57:55
虽有智慧,不如乘势;虽有鎡基,不如待时。
君子学以聚之,问以辨之,宽以居之,仁以行之。
独学而无友,则孤陋而寡闻。