【问题标题】:SQL Server: How to permission schemas?SQL Server:如何权限架构?
【发布时间】:2011-01-13 19:10:32
【问题描述】:

受到我见过的各种架构相关问题的启发......

Ownership chaining 允许我在没有明确权限的情况下对存储过程执行 GRANT EXECUTE 对我使用的表,如果存储过程和表都在同一个架构中。

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

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

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

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

当然,如果您使用 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:

  • 我们不使用“跨数据库所有权链接”
  • 行级安全性是一条红鲱鱼,无关紧要:我们不会在任何地方都使用它

【问题讨论】:

  • 为了清楚起见,是否可以提供您正在描述的单独架构场景的编码示例?在您的场景中,这两个独立的架构是否具有相同的所有者?
  • 为什么要为 serverfault 投票关闭?它适用于代码猴子,而不是系统管理员......

标签: sql-server-2005 sql-server-2008 permissions schema encapsulation


【解决方案1】:

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

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

关于您关于行级安全性的第二个问题:作为引擎提供的功能,SQL Server 2014 版及更早版本中并不真正存在行级安全性。您有各种变通方法,这些变通方法实际上与代码签名相比比所有权链接更好。由于sys.login_token 包含上下文签名和副署,因此您实际上可以进行比在所有权链接上下文中更复杂的检查。

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

【讨论】:

  • 行级安全实际上是一个红鲱鱼。我们也通过安全表中的 JOIN 使用 SUSER_SNAME 来控制访问。
  • 这是“遗留”位,然后是时间/努力/懒惰,为什么我没有跟进。无论如何+ 1。谢谢
【解决方案2】:

你可以:

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

允许用户执行模式中的任何过程。如果您不希望他能够执行所有这些,您可以明确拒绝对用户执行特定过程。在这种情况下,拒绝优先。

【讨论】:

  • 正确,但是存储过程使用的不同模式中的表呢?我不想否认任何权利
【解决方案3】:

我担心您的描述或您对所有权链的概念不清楚,所以让我从这个开始:

“所有权链接”只是指这样一个事实,即在 SQL Server 上执行存储过程(或视图)时,当前执行的批处理在执行时临时获取 sProc 的所有者(或 sProc 的架构的所有者)的权限/权限。 SQL 代码。因此,在 sProc 的情况下,用户不能使用这些 priv 来执行 sProc 代码没有为他们实现的任何事情。 特别注意,它永远不会获得所有者的身份,只是暂时获得它的权利(但是,EXECUTE AS... 会这样做)。

因此,利用它来提高安全性的典型方法是:

  1. 将所有数据表(以及所有非安全视图)放入它们自己的模式中,我们称之为 [data](尽管通常使用 [dbo],因为它已经存在并且对于用户的架构)。确保没有现有用户、架构或所有者有权访问此 [数据] 架构。

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

  3. 创建一个名为“Users”的新 db-Role,并为其授予对 [exec] 架构的 EXECUTE 访问权限。现在将所有用户添加到此角色。确保您的用户只有 Connect 权限,并且无权访问任何其他架构,包括 [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_

[编辑:代码的更正版本)

【讨论】:

  • 我通常通过这个例子理解所有权链接:schema1 中的存储过程访问 schema1 中的表 = 未检查表权限(包括 DENY)。例如,schema2 中的表被检查。我的示例表明,使用 EXEC MultiSchema1.P1
  • 我自己的例子与你的答案相冲突。我缺少的一点是,如果相关模式的 owner 相同,则不会检查权限。这就是我真正应该阅读的用户/模式分离的含义。但是,我们有 SQL 2005 之前的问题,并且没有考虑过
  • 该示例有效,因为它位于相同的架构中,因此存储的过程和表具有相同的所有者,因此允许访问,因为所有者始终具有 default 访问权限他们自己的东西。但是请注意,这不排除 DENY 等。任何可能阻止模式所有者的东西肯定会停止他们也拥有的存储过程。
  • 是的,它比最初看起来更加复杂和微妙。例如一个 sProc: dbo.FooBar can 有一个所有者 other 而不是 dbo(dbo 模式的所有者),在这种情况下它得到 that 所有者权利而不是 dbo 的权利。然而,这是更简单的安全方案(证书是更复杂(和 MS 首选)的方案)。 :-)
  • 行级安全性实际上是一个红鲱鱼。我们也通过安全表中的 JOIN 使用 SUSER_SNAME 来控制访问。
猜你喜欢
  • 2011-09-24
  • 1970-01-01
  • 2013-02-04
  • 1970-01-01
  • 2011-10-15
  • 2016-07-09
  • 1970-01-01
  • 2011-07-09
  • 2015-01-25
相关资源
最近更新 更多