Ceci est facile à réaliser de manière très sécurisée à l'aide de la signature de module. Ce sera similaire aux deux réponses suivantes, également ici sur DBA.StackExchange, qui donnent des exemples de cela:
Sécurité des procédures stockées avec exécution en tant que, requêtes de bases de données croisées et signature de module
Autorisations dans les déclencheurs lors de l'utilisation de certificats de bases de données croisées
La différence pour cette question particulière est qu'elle traite d'une vue et que les vues ne peuvent pas être signées. Ainsi, vous devrez changer la vue en une fonction table à valeurs multiples (TVF) car celles-ci peuvent être signées et accessibles comme une vue (enfin, pour l' SELECT
accès).
L'exemple de code suivant montre faire exactement ce qui est demandé dans la question en ce que le login / utilisateur "RestrictedUser" n'a accès qu'à "DatabaseA" et peut encore obtenir des données de "DatabaseB". Cela ne fonctionne qu'en sélectionnant celui-ci TVF , et uniquement en raison de sa signature.
La réalisation de ce type d'accès entre bases de données tout en utilisant une vue et en ne donnant à l'utilisateur aucune autorisation supplémentaire, nécessiterait l'activation du chaînage de propriété entre bases de données. C'est beaucoup moins sûr car il est complètement ouvert pour tous les objets entre les deux bases de données (il ne peut pas être limité à certains objets et / ou utilisateurs). La signature de module permet à ce seul TVF d'avoir un accès cross-DB (l'utilisateur n'a pas l'autorisation, le TVF en a), et les utilisateurs qui ne peuvent pas SELECT
depuis le TVF n'ont aucun accès à "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;
Toutes les étapes ci-dessus recréent la situation actuelle: l'utilisateur a accès à DatabaseA, a la permission d'interagir avec un objet dans DatabaseA, mais obtient une erreur car cet objet dans DatabaseA accède à quelque chose dans DatabaseB où l'utilisateur n'a aucun accès.
Les étapes ci-dessous configurent le module de chant. Il fait ce qui suit:
- crée un certificat dans DatabaseA
- Signe la TVF avec le certificat
- Copie le certificat (sans la clé privée) dans la base de données B
- Crée un utilisateur dans DatabaseB à partir du certificat
- Accorde l'
SELECT
autorisation à la table dans DatabaseB à l'utilisateur basé sur un certificat
Configuration de la signature du module:
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;
SI L'ACCÈS DOIT ÊTRE À TRAVERS UNE VUE, pour une raison quelconque, vous pouvez simplement créer une vue qui sélectionne à partir du TVF illustré ci-dessus. Et, dans cette situation, l' SELECT
accès n'a pas besoin d'être accordé à la TVF, mais uniquement à la vue, comme illustré ci-dessous:
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];
Et maintenant pour le tester:
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;
Pour plus d'informations sur la signature de module, veuillez visiter: https://ModuleSigning.Info/