Questo è facile da realizzare in un modo molto sicuro usando Module Signing. Questo sarà simile alle mie due risposte seguenti, anche qui su DBA.StackExchange, che forniscono esempi di questo:
Sicurezza delle procedure memorizzata con execute as, query tra database e firma del modulo
Autorizzazioni nei trigger quando si utilizzano certificati tra database
La differenza per questa particolare domanda è che si tratta di una vista e le viste non possono essere firmate. Quindi, sarà necessario modificare la vista in una funzione con valori di tabella (TVF) multi-istruzione poiché questi possono essere firmati e sono accessibili proprio come una vista (bene, per l' SELECT
accesso).
Il seguente codice di esempio mostra di fare esattamente ciò che viene richiesto nella domanda in quanto il login / utente "RestrictedUser" ha accesso solo a "DatabaseA" ed è ancora in grado di ottenere dati da "DatabaseB". Funziona solo selezionando da questo TVF e solo perché è stato firmato.
Per realizzare questo tipo di accesso tra database mentre si utilizza ancora una vista e non concedere all'utente ulteriori autorizzazioni, è necessario abilitare il concatenamento della proprietà tra database. Ciò è molto meno sicuro perché è completamente aperto per tutti gli oggetti tra i due database (non può essere limitato a determinati oggetti e / o Utenti). La firma del modulo consente solo a questo TVF di avere l'accesso tra DB (l'utente non ha l'autorizzazione, TVF lo fa) e gli utenti che non possono SELECT
accedere al TVF non hanno affatto accesso a "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;
Tutti i passaggi precedenti ricreano la situazione attuale: l'utente ha accesso a DatabaseA, dispone dell'autorizzazione per interagire con un oggetto in DatabaseA, ma riceve un errore a causa di tale oggetto in DatabaseA che accede a qualcosa in DatabaseB a cui l'utente non ha accesso.
I passaggi seguenti impostano il modulo Singing. Fa quanto segue:
- crea un certificato in DatabaseA
- Firma il TVF con il certificato
- Copia il certificato (senza chiave privata) nel database B
- Crea un utente in DatabaseB dal certificato
- Concede l'
SELECT
autorizzazione alla tabella in DatabaseB all'utente basato su certificato
Configurazione della firma del modulo:
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;
SE L'ACCESSO DOVREBBE ESSERE ATTRAVERSO UNA VISTA, per qualsiasi motivo, allora puoi semplicemente creare una Vista che seleziona dalla TVF mostrata sopra. E, in tale situazione, SELECT
non è necessario concedere l'accesso a TVF, ma solo a View, come dimostrato di seguito:
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];
E ora per testarlo:
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;
Per ulteriori informazioni sulla firma del modulo, visitare: https://ModuleSigning.Info/