Bua*_*aXD 2 schema security sql-server stored-procedures permissions
我在 SQL Server 2012 数据库中创建了一个用户,并撤销了该角色授予的所有权限public。
然后我授予了EXECUTE存储过程的权限。用户可以执行该过程,但无法获取其返回的数据。
该过程位于 中schema1,它从中选择的表位于 中schema2。
如果我将用户添加到db_datareader角色,它可以从数据库中的所有表中读取所有数据。我尝试使用WITH EXECUTE AS OWNER但没有成功。
我怎样才能只授予对给定过程的访问权限而不授予其他任何权限?
不,您不想要(或不需要)WITH EXECUTE AS OWNER。
问题很简单,您的两个模式(Schema1存储过程和Schema2表)具有不同的所有者。如果执行以下查询,您将看到谁拥有哪些架构:
SELECT *, USER_NAME([principal_id]) AS [UserName]
FROM sys.schemas;
Run Code Online (Sandbox Code Playgroud)
所有权链是默认的安全机制,如果所有者相同,则假定对正在访问的对象所引用的对象具有 DML 和 EXECUTE 权限。如果没有明确地将所有者分配给对象(默认 = NULL),则“所有者”被视为该对象所在架构的所有者。
因此,从技术上讲,您的模式可以具有相同的所有者,只是由于显式指定了表(通过ALTER AUTHORIZATION)而使表具有不同的所有者,但模式更有可能具有不同的所有者。
幸运的是,使用模块签名很容易解决这种情况。
其概念是在包含这些架构和对象的数据库中创建一个证书,然后使用该证书对存在于 中Schema1但从 中的表中进行选择的存储过程进行签名Schema2。
用户是根据证书创建的,然后被分配所需的任何权限,以便存储过程成功完成。
不会向将执行该存储过程的任何人授予任何权限。权限仅授予基于证书的用户。存储过程和基于证书的用户之间的连接(实际上)是证书的公钥。并且仅当执行使用该证书签名的模块时,该公钥才会加载到会话的安全上下文中。该签名需要证书的密码(在ADD SIGNATURE声明中),并且如果任何人更改了存储过程(或其所有者)的单个字节,该签名就会被删除。因此,非常安全。
下图说明了这个概念:
主要设置
CREATE SCHEMA [Schema1];
GO
CREATE SCHEMA [Schema2];
GO
CREATE USER [TestUser] WITHOUT LOGIN;
CREATE TABLE [Schema2].[Stuff]
(
[StuffID] INT NOT NULL IDENTITY(1, 1)
CONSTRAINT [PK_Stuff] PRIMARY KEY,
[Stuff] NVARCHAR(50) NOT NULL
);
INSERT INTO [Schema2].[Stuff] ([Stuff]) VALUES (N'Success!!');
GO
CREATE PROCEDURE [Schema1].[GetStuff]
AS
SET NOCOUNT ON;
SELECT [StuffID], [Stuff]
FROM [Schema2].[Stuff];
GO
GRANT EXECUTE ON [Schema1].[GetStuff] TO [TestUser];
Run Code Online (Sandbox Code Playgroud)
测试相同的架构所有者
EXECUTE AS USER = N'TestUser';
SELECT SUSER_NAME() AS [Login], USER_NAME() AS [User];
EXEC [Schema1].[GetStuff];
-- Success due to both Schemas having same owner
REVERT;
SELECT SUSER_NAME() AS [Login], USER_NAME() AS [User];
Run Code Online (Sandbox Code Playgroud)
再现现状
SELECT *, USER_NAME([principal_id]) AS [UserName]
FROM sys.schemas
WHERE [name] IN (N'Schema1', N'Schema2');
/*
name schema_id principal_id UserName
Schema1 5 1 dbo
Schema2 6 1 dbo
*/
ALTER AUTHORIZATION ON SCHEMA::[Schema2] TO [guest];
SELECT *, USER_NAME([principal_id]) AS [UserName]
FROM sys.schemas
WHERE [name] IN (N'Schema1', N'Schema2');
/*
name schema_id principal_id UserName
Schema1 5 1 dbo
Schema2 6 2 guest
*/
Run Code Online (Sandbox Code Playgroud)
测试当前情况(无额外权限)
EXECUTE AS USER = N'TestUser';
SELECT SUSER_NAME() AS [Login], USER_NAME() AS [User];
EXEC [Schema1].[GetStuff];
-- ERROR:
/*
Msg 229, Level 14, State 5, Procedure Schema1.GetStuff, Line XXXXX [Batch Start Line YYYYY]
The SELECT permission was denied on the object 'Stuff', database '......', schema 'Schema2'.
*/
REVERT;
SELECT SUSER_NAME() AS [Login], USER_NAME() AS [User];
Run Code Online (Sandbox Code Playgroud)
模块签名设置
-- Create Certificate and sign Stored Procedure with it:
CREATE CERTIFICATE [Permission$Schema2]
ENCRYPTION BY PASSWORD = 'SomePassword'
WITH SUBJECT = 'Used for selecting from objects in Schema2',
EXPIRY_DATE = '2099-12-31';
ADD SIGNATURE
TO [Schema1].[GetStuff]
BY CERTIFICATE [Permission$Schema2]
WITH PASSWORD = 'SomePassword';
-- Create Certificate-based User to hold permissions
CREATE USER [Permission$Schema2]
FROM CERTIFICATE [Permission$Schema2];
-- Grant Certificate-based User ONLY the permissions needed
GRANT SELECT ON SCHEMA::[Schema2] TO [Permission$Schema2];
Run Code Online (Sandbox Code Playgroud)
使用模块签名进行测试
EXECUTE AS USER = N'TestUser';
SELECT SUSER_NAME() AS [Login], USER_NAME() AS [User];
EXEC [Schema1].[GetStuff];
-- 1 Success!!!
REVERT;
SELECT SUSER_NAME() AS [Login], USER_NAME() AS [User];
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5734 次 |
| 最近记录: |