使用模块签名很容易以非常安全的方式完成此操作。这将与下面的两个答案类似,也在DBA.StackExchange上,给出了执行此操作的示例:
具有执行方式,跨数据库查询和模块签名的存储过程安全性
使用跨数据库证书时触发器中的权限
此特定问题的不同之处在于,它处理一个视图,并且无法对视图进行签名。因此,您将需要将View更改为多语句表值函数(TVF),因为可以对它们进行签名并且可以像View一样对其进行访问(嗯,可以SELECT
访问)。
下面的示例代码显示了该问题所要求的内容,即登录名/用户“ RestrictedUser”仅有权访问“ DatabaseA”,但仍能够从“ DatabaseB”获取数据。仅通过从一个TVF中进行选择,并且仅由于已对其进行签名,才能起作用。
要在仍然使用View的情况下实现这种跨数据库访问,并且不给用户任何其他权限,则需要启用跨数据库所有权链接。它的安全性要差得多,因为它对两个数据库之间的所有对象都是完全开放式的(不能仅限于某些对象和/或用户)。模块签名仅允许该一个TVF拥有跨数据库访问权限(用户没有权限,TVF拥有权限),并且不能SELECT
从TVF获得权限的用户根本无法访问“ DatabaseB”。
USE [master];
CREATE LOGIN [RestrictedUser] WITH PASSWORD = 'No way? Yes way!';
GO
---
USE [DatabaseA];
CREATE USER [RestrictedUser] FOR LOGIN [RestrictedUser];
GO
CREATE FUNCTION dbo.DataFromOtherDB()
RETURNS @Results TABLE ([SomeValue] INT)
AS
BEGIN
INSERT INTO @Results ([SomeValue])
SELECT [SomeValue]
FROM DatabaseB.dbo.LotsOfValues;
RETURN;
END;
GO
GRANT SELECT ON dbo.[DataFromOtherDB] TO [RestrictedUser];
GO
---
USE [DatabaseB];
CREATE TABLE dbo.[LotsOfValues]
(
[LotsOfValuesID] INT IDENTITY(1, 1) NOT NULL
CONSTRAINT [PK_LotsOfValues] PRIMARY KEY,
[SomeValue] INT
);
INSERT INTO dbo.[LotsOfValues] VALUES
(1), (10), (100), (1000);
GO
---
USE [DatabaseA];
SELECT * FROM dbo.[DataFromOtherDB]();
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
REVERT;
上面的所有步骤都重新创建了当前状况:用户有权访问DatabaseA,有权与DatabaseA中的对象进行交互,但是由于DatabaseA中的该对象访问了DatabaseB中的用户无法访问的内容而导致错误。
以下步骤设置了模块唱歌。它执行以下操作:
- 在DatabaseA中创建证书
- 用证书签署TVF
- 将证书(无私钥)复制到数据库B
- 从证书在DatabaseB中创建一个用户
- 授予
SELECT
权限表中DatabaseB的基于证书的用户
模块签名设置:
CREATE CERTIFICATE [AccessOtherDB]
ENCRYPTION BY PASSWORD = 'SomePassword'
WITH SUBJECT = 'Used for accessing other DB',
EXPIRY_DATE = '2099-12-31';
ADD SIGNATURE
TO dbo.[DataFromOtherDB]
BY CERTIFICATE [AccessOtherDB]
WITH PASSWORD = 'SomePassword';
---
DECLARE @CertificatePublicKey NVARCHAR(MAX) =
CONVERT(NVARCHAR(MAX), CERTENCODED(CERT_ID(N'AccessOtherDB')), 1);
SELECT @CertificatePublicKey AS [Cert / PublicKey]; -- debug
EXEC (N'USE [DatabaseB];
CREATE CERTIFICATE [AccessOtherDB] FROM BINARY = ' + @CertificatePublicKey + N';');
---
EXEC (N'
USE [DatabaseB];
CREATE USER [AccessOtherDbUser] FROM CERTIFICATE [AccessOtherDB];
GRANT SELECT ON dbo.[LotsOfValues] TO [AccessOtherDbUser];
');
---
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
-- Success!!
SELECT * FROM [DatabaseB].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
REVERT;
如果出于某种原因需要通过视图进行访问,则只需创建一个视图即可从上面显示的TVF中进行选择。而且,在这种情况下,SELECT
不访问没有需要被授予TVF,只能查看,这表现如下:
GO
CREATE VIEW dbo.[DataFromTVF]
AS
SELECT [SomeValue]
FROM dbo.DataFromOtherDB();
GO
-- Remove direct access to the TVF as it is no longer needed:
REVOKE SELECT ON dbo.[DataFromOtherDB] FROM [RestrictedUser];
GRANT SELECT ON dbo.[DataFromTVF] TO [RestrictedUser];
现在进行测试:
EXECUTE AS LOGIN = 'RestrictedUser';
SELECT * FROM dbo.[DataFromOtherDB]();
/*
Msg 229, Level 14, State 5, Line XXXXX
The SELECT permission was denied on the object 'DataFromOtherDB',
database 'DatabaseA', schema 'dbo'.
*/
SELECT * FROM [OwnershipChaining].[dbo].[LotsOfValues];
/*
Msg 916, Level 14, State 1, Line XXXXX
The server principal "RestrictedUser" is not able to access
the database "DatabaseB" under the current security context.
*/
SELECT * FROM dbo.[DataFromTVF];
-- Success!!
REVERT;
有关模块签名的更多信息,请访问:https : //ModuleSigning.Info/