Beg*_*DBA 5 security sql-server permissions sql-server-2012
我有一个名为数据库B的受限数据库(包含机密数据),只有几个用户可以访问它。但是,我需要从B 中的几个表中选择一些数据以供请求它的用户使用。请求数据的用户不会作为数据库用户添加到数据库B,因为他们不允许访问。但是,这些用户有权访问数据库A(他们被添加为 DB A 的数据库用户)。有没有办法让存储过程访问机密数据库(B),以便任何运行 SP 的用户都可以获得他们请求的数据?如果是这样,如何?我研究过这是可能的,但没有提到如何。
注意:通过 IS 包将所需数据从数据库B移动到A不是一个选项(需要实时访问)。我也考虑过使用视图(但同样,如何?如果您无权访问基表,您也将无法通过视图访问数据)。

这相当容易完成(包括处理多个数据库和动态 SQL),无需任何模拟(IMPERSONATE权限)、跨数据库所有权链接(服务器/实例或数据库设置)或TRUSTWORTHY(数据库设置)。一般来说,你需要做的是:
例子:
清理
USE [master];
GO
IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'DatabaseA')
BEGIN
PRINT 'Dropping [DatabaseA] DB...';
ALTER DATABASE [DatabaseA] SET OFFLINE WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [DatabaseA] SET ONLINE;
DROP DATABASE [DatabaseA];
END;
IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'DatabaseB')
BEGIN
PRINT 'Dropping [DatabaseB] DB...';
ALTER DATABASE [DatabaseB] SET OFFLINE WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [DatabaseB] SET ONLINE;
DROP DATABASE [DatabaseB];
END;
IF (SUSER_ID(N'JohnnyLunchbucket') IS NOT NULL)
BEGIN
PRINT 'Dropping [JohnnyLunchbucket] Login...';
DROP LOGIN [JohnnyLunchbucket];
END;
IF (OBJECT_ID(N'tempdb..#CertInfo') IS NOT NULL)
BEGIN
PRINT 'Dropping [#CertInfo] Temp Table...';
DROP TABLE #CertInfo;
END;
Run Code Online (Sandbox Code Playgroud)
设置
USE [master];
EXECUTE AS LOGIN = N'sa';
PRINT 'Creating databases...';
CREATE DATABASE [DatabaseA] COLLATE Latin1_General_100_CI_AS_SC;
CREATE DATABASE [DatabaseB] COLLATE Latin1_General_100_CI_AS_SC;
REVERT;
GO
ALTER DATABASE [DatabaseA] SET DB_CHAINING OFF;
ALTER DATABASE [DatabaseA] SET TRUSTWORTHY OFF;
ALTER DATABASE [DatabaseB] SET DB_CHAINING OFF;
ALTER DATABASE [DatabaseB] SET TRUSTWORTHY OFF;
GO
CREATE LOGIN [JohnnyLunchbucket] WITH PASSWORD = 'OhSoSecure;)';
USE [DatabaseA];
CREATE USER [JohnnyLunchbucket] FOR LOGIN [JohnnyLunchbucket];
GO
CREATE PROCEDURE dbo.RunReport
AS
SET NOCOUNT ON;
SELECT * FROM [DatabaseB].[dbo].[RestrictedTable];
GO
GRANT EXECUTE ON dbo.RunReport TO [JohnnyLunchbucket];
CREATE CERTIFICATE [PermissionsCert]
AUTHORIZATION [dbo]
ENCRYPTION BY PASSWORD = 'WeakPassword'
WITH SUBJECT = 'Used to test granting permissions to code',
EXPIRY_DATE = '2099-12-31';
ADD SIGNATURE TO [dbo].[RunReport]
BY CERTIFICATE [PermissionsCert]
WITH PASSWORD = 'WeakPassword';
SELECT CERTENCODED(CERT_ID(N'PermissionsCert')) AS [PublicKey],
CERTPRIVATEKEY(CERT_ID(N'PermissionsCert'), 'OtherPassword', 'WeakPassword')
AS [PrivateKey]
INTO #CertInfo;
GO
USE [DatabaseB];
DECLARE @SQL NVARCHAR(MAX);
SELECT @SQL = N'CREATE CERTIFICATE [PermissionsCert] AUTHORIZATION [dbo] FROM BINARY = '
+ CONVERT(NVARCHAR(MAX), [PublicKey], 1)
+ N' WITH PRIVATE KEY (BINARY = '
+ CONVERT(NVARCHAR(MAX), [PrivateKey], 1)
+ N', DECRYPTION BY PASSWORD = N''OtherPassword'''
+ N', ENCRYPTION BY PASSWORD = ''WeakPassword'');'
FROM #CertInfo;
PRINT @SQL;
EXEC (@SQL);
CREATE USER [PermissionsUser] FROM CERTIFICATE [PermissionsCert];
CREATE TABLE dbo.[RestrictedTable]
(
[ID] INT NOT NULL IDENTITY(1, 1)
CONSTRAINT [PK_RestrictedTable] PRIMARY KEY,
[Other] VARCHAR(50)
);
GRANT SELECT ON [dbo].[RestrictedTable] TO [PermissionsUser];
INSERT INTO dbo.[RestrictedTable] ([Other]) VALUES ('Ta da!');
GO
Run Code Online (Sandbox Code Playgroud)
测试
-- Quick test to show that [PermissionsUser] cannot be Impersonated:
USE [DatabaseB];
EXECUTE AS USER = 'PermissionsUser';
/*
Msg 15517, Level 16, State 1, Line 123
Cannot execute as the database principal because the principal "PermissionsUser" does not
exist, this type of principal cannot be impersonated, or you do not have permission.
*/
-- Main test:
USE [DatabaseA];
EXECUTE AS LOGIN = 'JohnnyLunchbucket';
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
GO
SELECT * FROM [DatabaseB].[dbo].[RestrictedTable];
/*
Msg 916, Level 14, State 1, Line 144
The server principal "JohnnyLunchbucket" is not able to access the database "DatabaseB"
under the current security context.
*/
EXEC [dbo].[RunReport]; -- SUCCESS!!!
-- 1 Ta da!
REVERT;
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
GO
Run Code Online (Sandbox Code Playgroud)
有关模拟与模块签名的更多信息,您可以查看我的另一个答案(以及其中链接的答案):