이것은 모듈 서명을 사용하여 매우 안전한 방법으로 달성하기 쉽습니다. 이것은 DBA.StackExchange의 다음 두 가지 대답과 비슷합니다.
실행 계정, 데이터베이스 간 쿼리 및 모듈 서명을 사용한 저장 프로 시저 보안
교차 데이터베이스 인증서를 사용할 때 트리거의 권한
이 특정 질문의 차이점은 뷰를 다루고 뷰에 서명 할 수 없다는 것입니다. 따라서 뷰를 서명과 같이 액세스하고 액세스 할 수 있으므로 TVF (Multi-Statement Table-Valued Function)로 뷰를 변경해야합니다 SELECT
.
다음 예제 코드는 로그인 / 사용자 "RestrictedUser"가 "DatabaseA"에만 액세스 할 수 있지만 "DatabaseB"에서 데이터를 가져올 수 있다는 점에서 질문에서 요청한 내용을 정확하게 수행하는 것을 보여줍니다. 이것은 하나의 TVF에서 선택 해야하며 서명되어 있기 때문에 가능합니다.
뷰를 계속 사용하면서 사용자에게 추가 권한을 부여 하지 않고이 유형의 데이터베이스 간 액세스를 수행 하려면 데이터베이스 간 소유권 체인을 활성화해야합니다. 두 데이터베이스 사이의 모든 객체에 대해 완전히 개방되어 있기 때문에 훨씬 안전하지 않습니다 (특정 객체 및 / 또는 사용자로 제한 할 수 없음). 모듈 서명을 사용하면이 TVF 하나만 DB 간 액세스 권한을 가질 수 있으며 (사용자 SELECT
는 TVF 권한을 갖지 못하고) 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에서 선택하는보기를 간단히 만들 수 있습니다. 이러한 상황에서 아래에 설명 된 것처럼 TVF에 SELECT
대한 액세스 권한은 보기에만 허용 되지 않아도됩니다.
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/를 참조하십시오.