SQL跨架构存储过程权限问题

时间:2019-05-04 14:58:23

标签: sql sql-server tsql

给出一个简化的存储过程

CREATE OR ALTER PROCEDURE [FooSchema].[Foo]
AS
SELECT
    B.*,
    FROM [BarSchema].[Bar] AS B
    WHERE [...]

在FooSchema而不是BarSchema上向用户授予EXEC后,该存储过程将失败,并显示以下消息

The SELECT permission was denied on the object 'Bar',

有没有一种方法可以使用户访问[FooSchema]。[Foo]而不会暴露[BarSchema]。[Bar]的整个数据集是因为存储过程已经过滤掉了与此用户相关的数据。

2 个答案:

答案 0 :(得分:3)

最简单的选择是使用[WITH EXECUTE AS]语句,其中指定的用户名具有相关对象所需的确切权限。

CREATE OR ALTER PROCEDURE [FooSchema].[Foo]
WITH EXECUTE AS '<username>'
AS
SELECT
    B.*,
    FROM [BarSchema].[Bar] AS B
    WHERE [...]

答案 1 :(得分:2)

如果两个模式都由同一用户拥有,则将应用常规的所有权链接,并且对proc具有EXECUTE权限的用户不需要对基础对象的权限。用户将只能使用存储过程返回的数据,并且除非您明确授予他们这样做的权限,否则将无法对表执行临时查询。

例如:

CREATE USER SchemaOwner WITHOUT LOGIN;
ALTER AUTHORIZATION ON SCHEMA::FooSchema TO SchemaOwner;
ALTER AUTHORIZATION ON SCHEMA::BarSchema TO SchemaOwner;

另一种仅在模块范围内提供附加权限的方法是使用模块签名。

CREATE CERTIFICATE FooUserCertificate
   ENCRYPTION BY PASSWORD = '0bfuscatedPassword'
   WITH SUBJECT = 'Allow access to bar table';

CREATE USER FooUser FROM CERTIFICATE FooUserCertificate;

GRANT SELECT ON BarSchema.Bar TO FooUser;

ADD SIGNATURE TO FooSchema.Foo BY CERTIFICATE FooUserCertificate
    WITH PASSWORD = '0bfuscatedPassword';

ALTER CERTIFICATE FooUserCertificate REMOVE PRIVATE KEY;
GO

尽管更为复杂,但模块签名优于EXECUTE AS的优点在于,原始调用者的身份在执行期间得以保留,而不会在当前数据库中进行沙箱处理。这对于审核和跨数据库访问很有用。有关更多信息,请参见this article