25

由我见过的各种模式相关的问题的启发......SQL Server:如何权限模式?

Ownership chaining允许我授予对存储过程来执行不明确权限在我使用表,如果两个存储过程和表是在同一个模式。

如果我们使用单独的模式,那么我必须在不同模式表上明确地GRANT XXX。所有权链接示例表明。这意味着存储的proc执行用户可以直接读/写你的表。

这就像直接访问类中的实例变量,绕过getter/setters,破坏封装。

我们还使用行级安全来限制某人看到的内容,并将其应用于存储过程。

那么,我们如何维护模式分离并防止直接表访问呢?

当然,如果您使用ORM或不使用存储的特效,问题将不适用。但我不如果我应该使用的情况下,任何人都觉得需要赐教一个ORM或存储过程...

编辑,例如

CREATE USER OwnsMultiSchema WITHOUT LOGIN 
GO 
CREATE SCHEMA MultiSchema1 AUTHORIZATION OwnsMultiSchema 
GO 
CREATE SCHEMA MultiSchema2 AUTHORIZATION OwnsMultiSchema 
GO 

CREATE USER OwnsOtherSchema WITHOUT LOGIN 
GO 
CREATE SCHEMA OtherSchema AUTHORIZATION OwnsOtherSchema 
GO 

CREATE TABLE MultiSchema1.T1 (foo int) 
GO 
CREATE TABLE MultiSchema2.T2 (foo int) 
GO 
CREATE TABLE OtherSchema.TA (foo int) 
GO 

CREATE PROC MultiSchema1.P1 
AS 
SELECT * FROM MultiSchema1.T1 
SELECT * FROM MultiSchema2.T2 
SELECT * FROM OtherSchema.TA 
Go 
EXEC AS USER = 'OwnsMultiSchema' 
GO 
--gives error on OtherSchema 
EXEC MultiSchema1.P1 
GO 
REVERT 
GO 

CREATE PROC OtherSchema.PA 
AS 
SELECT * FROM MultiSchema1.T1 
SELECT * FROM MultiSchema2.T2 
SELECT * FROM OtherSchema.TA 
Go 
GRANT EXEC ON OtherSchema.PA TO OwnsMultiSchema 
GO 
EXEC AS USER = 'OwnsMultiSchema' 
GO 
--works 
EXEC OtherSchema.PA 
GO 
REVERT 
GO 

编辑2:

  • 我们不使用“跨数据库所有权链接”
  • 行级安全性是一个红色的鲱鱼和无关紧要的:我们不使用它无处不在
+2

为了清晰起见,您可以提供一个单独架构场景的代码示例吗?在你的场景中,两个独立的模式是否有相同的所有者? – 2010-02-06 06:52:48

+0

为什么投票关闭serverfault?这是代码猴子,而不是系统管理员... – gbn 2010-02-06 07:35:26

+0

@John Sansom:是的,我会的。 – gbn 2010-02-06 07:35:56

回答

21

我担心,或者您的描述或你的所有权链的概念还不清楚,所以让我先说:

“所有权链”仅仅指的是事实,执行存储过程(或视图)上时, SQL Server中,当前正在执行的批处理在执行该SQL代码时临时获取sProc的所有者(或sProc的模式所有者)的权限。因此,在sProc的情况下,用户不能使用这些特权来执行sProc代码无法为其执行的任何操作。 尤其要注意,它永远不会获得所有者的标识,只是它的权利,暂时(但是,EXECUTE AS ...确实这样做)。

因此,典型的方法来利用这个安全是:

  1. 把所有的数据表(和所有非安全性的意见,以及)到自己的架构,让我们把它[数据](尽管通常会使用[dbo],因为它已经存在并且对于用户的模式而言具有特权)。确保没有现有的用户,模式或所有者有权访问此[数据]模式。

  2. 为所有sProcs(和/或可能的任何安全性视图)创建一个名为[exec]的模式。确保此架构的所有者可以访问[数据]架构(如果您将dbo作为此架构的所有者,这很容易)。

  3. 创建一个名为“Users”的新db-Role并赋予其EXECUTE访问[exec]模式的权限。现在将所有用户添加到此角色。确保你的用户只有连接权限,并且没有对任何其他模式的授权访问权限,包括[dbo]。

现在您的用户只能通过在[exec]中执行sProcs来访问数据。他们不能访问任何其他数据或执行任何其他对象。

我不确定这是否回答你的问题(因为我不确定问题究竟是什么),所以请随意重定向我。


至于行级安全性,这里是如何,我总是与上面的安全方案做:

  1. 我总是实现行级安全性为一系列意见的那面镜子,包裹每个表并将用户的身份(通常与Suser_Sname()或其他人的身份)进行比较,并将其与行中的安全代码键入的安全列表进行比较。这些是安全视图。

  2. 创建一个名为[rows]的新模式,赋予其所有者对[data]模式的访问权限,而不是其他任何东西。将所有的安全视图放在这个模式中。

  3. 撤消[exec]所有者对[data]模式的访问权,并将其授予[rows]模式的数据访问权。

完成。现在通过在sProcs和表之间透明地滑动行来实现行级安全性。


最后,这里是一个存储促使我用它来帮助自己记住多少,这不起眼的安全的东西的作品,并与自身相互作用(哎呀,纠正版本的代码):

CREATE proc [TestCnxOnly].[spShowProc_Security_NoEX] as 
--no "With Execute as Owner" for this version 
--create User [UserNoLogin] without login 
--Grant connect on database :: TestSecurity to Guest 
--alter database TestSecurity set trustworthy on 

--Show current user context: 
select current_user as current_ 
, session_user as session 
, user_name() as _name 
, suser_name() as [suser (sproc)] 
, suser_sname() as sname 
, system_user as system_ 


--Execute As Login = 'UserNoLogin' 
select current_user as current_ 
, session_user as session 
, user_name() as _name 
, suser_name() as [suser (after exec as)] 
, suser_sname() as sname 
, system_user as system_ 

EXEC('select current_user as current_ 
, session_user as session 
, user_name() as _name 
, suser_name() as [suser (in Exec(sql))] 
, suser_sname() as sname 
, system_user as system_') 

EXEC sp_ExecuteSQL N'select current_user as current_ 
, session_user as session 
, user_name() as _name 
, suser_name() as [suser (in sp_Executesql)] 
, suser_sname() as sname 
, system_user as system_' 

--Revert 
select current_user as current_ 
, session_user as session 
, user_name() as _name 
, suser_name() as [suser (aftr revert)] 
, suser_sname() as sname 
, system_user as system_ 

[编辑:修正版本的代码]

+0

我通常理解这个例子的所有权链接:schema1中的存储过程访问表schema1 =表权限(包括DENY)中的表未检查。例如schema2中的表被检查。我的例子表明,用EXEC MultiSchema1.P1 – gbn 2010-02-06 09:00:36

+0

我自己的例子与你的答案交叉。我缺少的是如果相关模式的*所有者*是相同的,那么权限不被检查。这就是我真正应该阅读的用户/模式分离的含义。但是,我们有SQL 2005的预处理,并没有考虑到它通过 – gbn 2010-02-06 09:14:10

+0

该示例的工作原理是因为它位于相同的模式中,因此存储的proc和表具有相同的所有者,因此允许访问,因为所有者始终具有* default *访问权限到自己的东西。但是,请注意,这不是排除DENY等。任何可能阻止架构所有者的事情都会阻止他们拥有的存储特效。 – RBarryYoung 2010-02-06 09:14:14

4

您可以:

Grant Execute On Schema::[schema_name] To [user_name] 

,以允许用户在架构中执行任何程序。如果您不希望他能够执行所有这些操作,则可以显式拒绝对用户执行特定过程的执行。在这种情况下,Deny将优先。

+0

正确,但存储过程使用的不同架构中的表又如何?我不想拒绝任何权利 – gbn 2010-02-06 08:35:33

8

我的2c:所有权链接是遗留的。它从没有替代品的日子开始,与今天的替代品相比是不安全和粗糙的。

我说的替代方案不是模式权限,替代方案是代码签名。通过代码签名,您可以授予对过程签名所需的权限,并在严格控制数据访问的同时授予对过程的广泛执行访问权限。代码签名提供更细化和更精确的控制,并且不能以所有权链接的方式滥用。它在模式内部工作,它可以跨架构工作,它可以跨数据库工作,并且不需要跨数据库所有权链接的巨大安全漏洞打开。它不需要劫持对象所有权以用于访问目的:该过程的所有者可以是任何用户。

至于你关于行级安全性的第二个问题:作为引擎提供的一项功能,SQL Server 2014及更早版本中并不存在行级安全性。您有各种解决方法,而且这些解决方法在代码签名方面的效果要比使用所有权链接效果更好。由于sys.login_token包含上下文签名和联署,因此实际上可以执行比所有权链接上下文更复杂的检查。

自2016版以来,SQL Server完全支持row level security

+0

行级安全性实际上是一个红鲱鱼..我们也通过安全表的JOIN来控制访问,我们也使用SUSER_SNAME。 – gbn 2010-02-06 09:20:26

+0

这是“遗产”,然后是时间/精力/懒惰,为什么我没有跟进。 + 1无论如何。谢谢 – gbn 2010-02-06 09:28:26