SQL Server:权限模式如何?

时间:2010-02-06 04:21:23

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

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

Ownership chaining允许我对存储过程进行GRANT EXECUTE,如果存储过程和表都在同一模式中,则对我使用的表没有显式权限。

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

这就像直接访问类中的实例变量一样,绕过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:

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

3 个答案:

答案 0 :(得分:22)

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

“Ownership Chaining”只是指在SQL Server上执行存储过程(或View)时,当前正在执行的批处理在执行时临时获取sProc所有者(或sProc的架构所有者)的权限/权限。 SQL代码。因此,对于sProc,用户不能使用这些priv来执行sProc代码未实现的任何操作。 特别注意,它永远不会获得所有者的身份,只会暂时获取它的权利(但是,EXECUTE AS ...会这样做)。

因此,将此用于安全性的典型方法是:

  1. 将所有数据表(以及所有非安全性视图)放入他们自己的Schema中,让我们称之为[数据](虽然通常使用[dbo],因为它已经存在并且过于特权用户的架构)。确保没有现有的用户,架构或所有者可以访问此[数据]架构。

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

  3. 创建一个名为“Users”的新数据库角色,并为其提供对[exec]模式的EXECUTE访问权限。现在将所有用户添加到此角色。确保您的用户仅具有Connect权限,并且没有授予对任何其他架构的授予访问权限,包括[dbo]。

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

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


    至于行级安全性,以下是我总是采用上述安全方案的方法:

    1. 我总是将行级安全性实现为一系列视图,这些视图镜像包装每个表并将用户的身份(通常是Suser_Sname()或其中一个)与安全代码中的安全列表进行比较在行本身。这些是安全观点。

    2. 创建一个名为[rows]的新架构,让它的所有者访问[data]架构,而不是别的。将所有安全视图放在此架构中。

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

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


      最后,这是一个存储的采购,我用它来帮助我记住这些模糊的安全内容有多少起作用并与自身交互( oops,修正版本的代码):

      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_
      

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

答案 1 :(得分:8)

我的2c:所有权链接是遗产。它可以追溯到没有替代品的日子,与今天的替代品相比,它是不安全和粗糙的。

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

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

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

答案 2 :(得分:4)

你可以:

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

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