Dostęp do widoku na podstawie tabeli w innej bazie danych bez konta w tej innej bazie danych

11

Utworzyłem widok w bazie danych 1 na podstawie tabel w bazie danych 2. Dałem SELECTzgodę użytkownikowi, który ma dostęp tylko do bazy danych 1. Użytkownik nie może uruchomić tego widoku, ponieważ nie ma konta w bazie danych2. Jak mogę rozwiązać ten problem? Nie chcę tworzyć konta w bazie danych2.

Tomek
źródło
1
@mustaccio Nie, to nie jest duplikat tego drugiego pytania / odpowiedzi, ponieważ cała sytuacja znajdowała się w tej samej bazie danych, a to pytanie dotyczy baz danych. Domyślnie jest to niedozwolone. Trzeba byłoby włączyć tworzenie łańcuchów własności między bazami danych i jest to ogromna luka w zabezpieczeniach, którą można otworzyć w przypadku tak wąskiej potrzeby.
Solomon Rutzky,
1
@ SolomonRutzky, nie nazwałbym DB_CHAINING „wielką dziurą bezpieczeństwa”. W typowych środowiskach produkcyjnych, w których tylko członkowie roli sysadmin mogą tworzyć obiekty, nie stanowi to problemu. To powiedziawszy, należy go używać ostrożnie w przypadkach, gdy członkowie roli niesysadmin mają uprawnienia do kontroli schematów innych niż te, których są właścicielami.
Dan Guzman,
@ DanGuzman „Zaufaj mi, wszystko zawsze pójdzie zgodnie z planem” nie jest skuteczną strategią. Zgodnie z tą logiką prawie nie ma ryzyka w ustawianiu TRUSTWORTHY ONlub logowaniu aplikacji jako sa. Łańcuchy własnościowe DB i TRUSTWORTHYistnieją głównie dlatego, że w tamtym czasie były jedynym rozwiązaniem. Ale teraz, nawet jeśli nie jest to duże ryzyko, Łańcuch DB jest z pewnością niepotrzebnym ryzykiem, ponieważ podpisywanie modułów nie jest takie trudne. A jeśli ktoś polega na tworzeniu łańcuchów DB, a następnie korzysta z Dynamicznego SQL, to jest większe prawdopodobieństwo TRUSTWORTHY ON, że to naprawi, podczas gdy przy podpisywaniu modułów nie złamie się.
Solomon Rutzky,
@ SolomonRutzky, sugerowałbym podpisanie modułu, gdyby pytanie dotyczyło modułu zamiast widoku. Uważam, że DB_CHAININGnie jest to bardziej ryzykowne niż tworzenie łańcuchów własności w obrębie bazy danych, gdy obiekty i tak powinny znajdować się w tej samej bazie danych.
Dan Guzman,
@ DanGuzman Po co zakładać, że „obiekty i tak powinny znajdować się w tej samej bazie danych”? OP wskazał tylko odwrotnie, ponieważ chcą oddzielić dostęp do DB. To, że OP używa Widoku, dlatego zasugerowałem TVF zamiast Procedury składowanej, ale to nie znaczy, że dalsze używanie Widoku jest najlepszym sposobem działania. Często sugeruje się modyfikowanie struktury i / lub podejścia, gdy ma to sens, jak ma to miejsce w tym przypadku. Nadal jednak do odpowiedzi dodałem opcjonalne opakowanie Zobacz. Biorąc pod uwagę, że posiadanie wszystkiego przez „dbo” najczęściej DB_CHAININGjest tak ryzykowne.
Solomon Rutzky,

Odpowiedzi:

9

Jest to łatwe do osiągnięcia w bardzo bezpieczny sposób przy użyciu podpisywania modułów. Będzie to podobne do poniższych dwóch moich odpowiedzi, również tutaj na DBA.StackExchange, które podają przykłady wykonania tego:

Zabezpieczenia procedur przechowywanych z wykonywaniem jako, zapytania do wielu baz danych i podpisywanie modułów

Uprawnienia w wyzwalaczach podczas korzystania z certyfikatów między bazami danych

Różnica w tym konkretnym pytaniu polega na tym, że dotyczy ono Widoku i Widoku nie można podpisać. Musisz więc zmienić widok na wielowątkową funkcję tabelową (TVF), ponieważ można je podpisać i uzyskać do nich dostęp podobnie jak widok (cóż, SELECTdostęp).

Poniższy przykładowy kod pokazuje robienie dokładnie tego, co jest wymagane w pytaniu, ponieważ Login / Użytkownik „RestrictedUser” ma dostęp tylko do „DatabaseA” i jest w stanie uzyskać dane z „DatabaseB”. Działa to tylko poprzez wybranie z tego jednego TVF i tylko z powodu jego podpisania.

Realizacji tego typu dostępu cross-bazy danych, jednocześnie korzystając z widoku, a nie dając użytkownikowi żadnych dodatkowych uprawnień, wymagałoby umożliwiając Cross-bazy danych własności łańcuchowym. Jest to o wiele mniej bezpieczne, ponieważ jest całkowicie otwarte dla wszystkich obiektów między obiema bazami danych (nie można go ograniczyć do niektórych obiektów i / lub użytkowników). Podpisywanie modułów pozwala tylko temu jednemu TVF na SELECTdostęp między bazami danych (użytkownik nie ma pozwolenia, TVF ma), a użytkownicy, którzy nie mogą z TVF, nie mają w ogóle dostępu do „Bazy danychB”.

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;

Wszystkie powyższe kroki odtwarzają bieżącą sytuację: użytkownik ma dostęp do bazy danych A, ma uprawnienia do interakcji z obiektem w bazie danych A, ale dostaje błąd z powodu tego, że obiekt w bazie danych uzyskuje dostęp do czegoś w bazie danych b, do którego użytkownik nie ma dostępu.

Poniższe kroki konfigurują śpiewanie modułów. Wykonuje następujące czynności:

  1. tworzy certyfikat w bazie danych A.
  2. Podpisuje TVF certyfikatem
  3. Kopiuje certyfikat (bez klucza prywatnego) do bazy danych B
  4. Tworzy użytkownika w bazie danychB na podstawie certyfikatu
  5. Nadaje SELECTuprawnienia do tabeli w bazie danych B użytkownikowi opartemu na certyfikatach

Konfiguracja podpisywania modułów:

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;

JEŚLI DOSTĘP POTRZEBUJE PRZEZ WIDOK, z jakiegokolwiek powodu, możesz po prostu utworzyć Widok, który wybierze z TVF pokazanego powyżej. W tej sytuacji SELECTdostęp nie musi być przyznany TVF, a jedynie widokowi, jak pokazano poniżej:

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];

A teraz, aby to przetestować:

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;

Aby uzyskać więcej informacji na temat podpisywania modułów, odwiedź: https://ModuleSigning.Info/

Solomon Rutzky
źródło
Czy kopie zapasowe certyfikatów są wykonywane w ramach regularnych kopii zapasowych? A może są przechowywane gdzie indziej i również wymagają kopii zapasowej systemu plików? A co się stanie, jeśli przywrócisz do niższego środowiska, które może używać różnych haseł itp.?
Chris Aldrich
@ChrisAldrich W pokazanym tutaj zastosowaniu kopia zapasowa jest tworzona za pomocą bazy danych, ponieważ jest w całości przechowywana w bazie danych. Jeśli go użyjesz, ALTER CERTIFICATE ... DROP PRIVATE KEYklucz prywatny zniknie, jeśli nie utworzysz go najpierw do pliku przy użyciu CERTYFIKATU BACKUP . Ale klucz publiczny jest nadal włączonysys.certificates . A klucz publiczny nie potrzebuje hasła. Tylko użycie klucza prywatnego do podpisania modułu wymaga hasła (które jest takie samo na wszystkich serwerach, w przeciwieństwie do ochrony za pomocą klucza głównego).
Solomon Rutzky