Accedi alla vista in base alla tabella in un altro database senza account in quell'altro database


10

Ho creato la vista in database1 in base alle tabelle in database2. Ho concesso l' SELECTautorizzazione a un utente che ha accesso solo al database1. L'utente non può far funzionare questa vista perché non ha un account in database2. Come posso risolvere questo problema? Non voglio creare un account in database2.


1
@mustaccio No, questo non è un duplicato di quell'altra domanda / risposta poiché quella situazione era tutta all'interno dello stesso database e questa domanda riguarda lo spanning dei database. Per impostazione predefinita, questo non è consentito. Uno dovrebbe consentire il concatenamento della proprietà tra database e questo è un enorme buco di sicurezza da aprire per un'esigenza così ristretta.
Solomon Rutzky,

1
@SolomonRutzky, non definirei DB_CHAINING un "enorme buco di sicurezza". In ambienti di produzione tipici in cui solo i membri del ruolo di amministratore di sistema possono creare oggetti, non si tratta di un problema. Detto questo, dovrebbe essere usato con attenzione nei casi in cui i membri del ruolo non amministratore di sistema hanno autorizzazioni di controllo su schemi diversi da quelli di loro proprietà.
Dan Guzman,

@DanGuzman "Fidati di me, tutto andrà sempre secondo i piani" non è una strategia efficace. In base a tale logica, non c'è quasi alcun rischio nell'impostare TRUSTWORTHY ONo avere l'accesso come sa. DB Ownership Chaining ed TRUSTWORTHYesiste principalmente per essere l'unica soluzione al momento. Ma ora, anche se non un rischio enorme, DB Chaining è certamente un rischio non necessario poiché la firma del modulo non è così difficile. E se si fa affidamento sul concatenamento di DB e quindi si utilizza Dynamic SQL, è più probabile che si impostino TRUSTWORTHY ONper risolverlo, mentre con Module Signing non si sarebbe rotto.
Solomon Rutzky,

@ SolomonRutzky, avrei suggerito la firma del modulo se la domanda riguardasse un modulo anziché una vista. Il mio pensiero è che DB_CHAININGnon è più rischioso del concatenamento della proprietà all'interno del database quando gli oggetti avrebbero dovuto essere comunque nello stesso database.
Dan Guzman,

@DanGuzman Perché supporre che "gli oggetti avrebbero dovuto essere comunque nello stesso database"? L'OP ha indicato il contrario solo perché vogliono mantenere separato l'accesso al DB. Il fatto che l'OP stia utilizzando una vista è il motivo per cui ho suggerito una TVF anziché una Stored procedure, ma ciò non significa che continuare a utilizzare una vista sia la migliore linea d'azione. È comune suggerire di modificare la struttura e / o l'approccio quando ha senso farlo, come nel caso qui. Tuttavia, ho aggiunto una vista wrapper opzionale alla mia risposta. E, dato che è più comune per "dbo" possedere tutto, sì, DB_CHAININGè abbastanza rischioso.
Solomon Rutzky,

Risposte:


9

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' SELECTaccesso).

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 SELECTaccedere 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:

  1. crea un certificato in DatabaseA
  2. Firma il TVF con il certificato
  3. Copia il certificato (senza chiave privata) nel database B
  4. Crea un utente in DatabaseB dal certificato
  5. Concede l' SELECTautorizzazione 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, SELECTnon è 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/


Viene eseguito il backup dei certificati come parte dei backup regolari? O sono memorizzati altrove e richiedono anche un backup del file system? E cosa succede se si ripristina in un ambiente inferiore che può utilizzare password diverse, ecc.?
Chris Aldrich,

@ChrisAldrich Nell'uso mostrato qui, viene eseguito il backup con il DB poiché è interamente contenuto nel database. Se si utilizza, ALTER CERTIFICATE ... DROP PRIVATE KEYla chiave privata sparirebbe se non si eseguisse prima il backup su un file utilizzando il CERTIFICATO DI BACKUP . Ma la chiave pubblica è ancora in sys.certificates. E la chiave pubblica non ha bisogno della password. L'uso della chiave privata per firmare un modulo richiede solo la password (che è la stessa tra i server, diversamente dalla protezione tramite chiave master).
Solomon Rutzky,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.