Dies ist mit Module Signing auf sehr sichere Weise einfach zu bewerkstelligen. Dies ähnelt den folgenden zwei Antworten von mir, auch hier auf DBA.StackExchange, die Beispiele dafür geben:
Sicherheit gespeicherter Prozeduren mit Ausführung als, datenbankübergreifenden Abfragen und Modulsignatur
Berechtigungen in Triggern bei Verwendung datenbankübergreifender Zertifikate
Der Unterschied für diese spezielle Frage besteht darin, dass es sich um eine Ansicht handelt und Ansichten nicht signiert werden können. Daher müssen Sie die Ansicht in eine TVF-Funktion (Table-Valued Function) mit mehreren Anweisungen ändern, da diese signiert werden können und wie eine Ansicht aufgerufen werden können (also für den SELECT
Zugriff).
Der folgende Beispielcode zeigt genau das, was in der Frage angefordert wird, da der Login / Benutzer "RestrictedUser" nur Zugriff auf "DatabaseA" hat und dennoch Daten aus "DatabaseB" abrufen kann. Dies funktioniert nur durch Auswahl aus diesem einen TVF und nur aufgrund dessen, dass es signiert ist.
Durchführen diese Art von Cross-Datenbank - Zugriff , während immer noch eine Ansicht verwenden, und nicht dem Benutzer zusätzliche Berechtigungen zu geben, würde ermöglichen Cross-Database Ownership Chaining erfordern. Dies ist weitaus weniger sicher, da es für alle Objekte zwischen beiden Datenbanken vollständig offen ist (es kann nicht auf bestimmte Objekte und / oder Benutzer beschränkt werden). Durch die Modulsignierung kann nur diese eine TVF auf die SELECT
Datenbank zugreifen (der Benutzer hat keine Berechtigung, die TVF hat dies), und Benutzer, die nicht über die TVF verfügen können, haben überhaupt keinen Zugriff auf "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;
Alle oben genannten Schritte stellen die aktuelle Situation wieder her: Der Benutzer hat Zugriff auf DatabaseA, hat die Berechtigung, mit einem Objekt in DatabaseA zu interagieren, erhält jedoch einen Fehler, weil dieses Objekt in DatabaseA auf etwas in DatabaseB zugreift, auf das der Benutzer keinen Zugriff hat.
Mit den folgenden Schritten wird das Modul-Singen eingerichtet. Es macht folgendes:
- erstellt ein Zertifikat in DatabaseA
- Unterzeichnet die TVF mit dem Zertifikat
- Kopiert das Zertifikat (ohne den privaten Schlüssel) in die Datenbank B.
- Erstellt einen Benutzer in DatabaseB aus dem Zertifikat
- Erteilt
SELECT
dem zertifikatbasierten Benutzer die Berechtigung für die Tabelle in DatenbankB
Modul-Signatur-Setup:
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;
Wenn der Zugriff aus irgendeinem Grund über eine Ansicht erfolgen muss, können Sie einfach eine Ansicht erstellen, die aus der oben gezeigten TVF ausgewählt wird. In dieser Situation SELECT
muss der TVF kein Zugriff gewährt werden, sondern nur der Ansicht, wie unten gezeigt:
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];
Und jetzt zum Testen:
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;
Weitere Informationen zum Modul-Signieren finden Sie unter: https://ModuleSigning.Info/