Akses tampilan berdasarkan tabel di database lain tanpa akun di database lain itu

10

Saya membuat tampilan di database1 berdasarkan tabel di database2. Saya memberikan SELECTizin kepada pengguna yang hanya memiliki akses ke database1. Pengguna tidak dapat membuat tampilan ini berfungsi karena ia tidak memiliki akun di database2. Bagaimana saya bisa mengatasi masalah ini? Saya tidak ingin membuat akun di database2.

tom
sumber
1
@mustaccio Tidak, ini bukan duplikat dari pertanyaan / jawaban lain karena situasinya semua dalam database yang sama, dan pertanyaan ini adalah tentang merentangkan basis data. Secara default itu tidak diizinkan. Kita harus mengaktifkan rantai kepemilikan lintas-basis data, dan itu adalah lubang keamanan besar untuk membuka untuk kebutuhan yang begitu sempit.
Solomon Rutzky
1
@ SolomonRutzky, saya tidak akan menyebut DB_CHAINING sebagai "lubang keamanan besar". Dalam lingkungan produksi yang khas di mana hanya anggota peran sysadmin yang dapat membuat objek, itu bukan masalah. Yang mengatakan, itu harus digunakan dengan hati-hati dalam kasus di mana anggota peran non-sysadmin memiliki izin kontrol pada skema selain yang mereka miliki.
Dan Guzman
@DanGuzman "Percayalah, semuanya akan selalu berjalan sesuai rencana" bukanlah strategi yang efektif. Dengan logika itu, hampir tidak ada risiko dalam pengaturan TRUSTWORTHY ONatau memiliki aplikasi masuk sebagai sa. Rantai Kepemilikan DB dan TRUSTWORTHYada terutama karena menjadi satu-satunya solusi pada saat itu. Tapi sekarang, bahkan jika bukan risiko besar, DB Chaining tentu saja risiko yang tidak perlu karena Modul Signing tidak sulit. Dan jika seseorang mengandalkan DB chaining dan kemudian menggunakan Dynamic SQL, mereka lebih cenderung TRUSTWORTHY ONuntuk memperbaikinya, sedangkan dengan Modul Penandatanganan itu tidak akan rusak.
Solomon Rutzky
@ SolomonRutzky, saya akan menyarankan penandatanganan modul jika pertanyaannya adalah tentang modul, bukan tampilan. Pemikiran saya adalah bahwa DB_CHAININGtidak lebih berisiko daripada rantai kepemilikan intra-database ketika objek seharusnya berada dalam database yang sama pula.
Dan Guzman
@DanGuzman Mengapa berasumsi bahwa "objek seharusnya berada di database yang sama?" OP hanya mengindikasikan sebaliknya karena mereka ingin memisahkan akses DB. Bahwa OP menggunakan View adalah mengapa saya menyarankan TVF daripada Stored Procedure, tetapi itu tidak berarti terus menggunakan View adalah tindakan terbaik. Adalah umum untuk menyarankan memodifikasi struktur dan / atau pendekatan ketika itu masuk akal untuk dilakukan, seperti halnya di sini. Namun, saya menambahkan Tampilan pembungkus opsional untuk jawaban saya. Dan, mengingat bahwa "dbo" yang paling umum memiliki segalanya, ya, DB_CHAININGsangat berisiko.
Solomon Rutzky

Jawaban:

9

Ini mudah dilakukan dengan cara yang sangat aman menggunakan Modul Signing. Ini akan serupa dengan dua jawaban saya berikut, juga di sini di DBA.StackExchange, yang memberikan contoh melakukan hal ini:

Keamanan prosedur tersimpan dengan eksekusi sebagai, kueri basis data lintas, dan penandatanganan modul

Izin di pemicu saat menggunakan sertifikat lintas basis data

Perbedaan untuk pertanyaan khusus ini adalah bahwa ia berkaitan dengan Tampilan, dan Tampilan tidak dapat ditandatangani. Jadi, Anda perlu mengubah Tampilan menjadi Fungsi Table-Valued (TVF) multi-pernyataan karena fungsi tersebut dapat ditandatangani dan dapat diakses seperti halnya Tampilan (well, for SELECTaccess).

Contoh kode berikut menunjukkan melakukan persis apa yang diminta dalam pertanyaan di mana Login / Pengguna "RestrictedUser" hanya memiliki akses ke "DatabaseA" dan belum bisa mendapatkan data dari "DatabaseB". Ini hanya berfungsi dengan memilih dari TVF yang satu ini , dan hanya karena itu ditandatangani.

Untuk mendapatkan akses lintas-basis data jenis ini saat masih menggunakan Tampilan, dan tidak memberikan izin tambahan kepada Pengguna, akan membutuhkan Pengaktifan Kepemilikan Lintas-Database. Itu jauh lebih tidak aman karena itu sepenuhnya terbuka untuk semua objek antara kedua Database (tidak dapat dibatasi untuk objek dan / atau Pengguna tertentu). Penandatanganan Modul memungkinkan TVF yang satu ini memiliki akses lintas-DB (Pengguna tidak memiliki izin, TVF memilikinya), dan Pengguna yang tidak dapat SELECTdari TVF tidak memiliki akses ke "DatabaseB" sama sekali.

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;

Semua langkah di atas menciptakan kembali situasi saat ini: Pengguna memiliki akses ke DatabaseA, memiliki izin untuk berinteraksi dengan objek di DatabaseA, tetapi mendapat kesalahan karena objek di DatabaseA mengakses sesuatu di DatabaseB di mana Pengguna tidak memiliki akses.

Langkah-langkah di bawah ini mengatur Modul Singing. Ini melakukan hal berikut:

  1. membuat Sertifikat di DatabaseA
  2. Menandatangani TVF dengan Sertifikat
  3. Menyalin Sertifikat (tanpa Kunci Pribadi) ke Basis Data B
  4. Menciptakan Pengguna di DatabaseB dari Sertifikat
  5. Memberikan SELECTizin ke Tabel di DatabaseB untuk Pengguna berbasis Sertifikat

Pengaturan Penandatanganan Modul:

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;

JIKA AKSES PERLU MELALUI PANDANGAN, untuk alasan apa pun, maka Anda dapat dengan mudah membuat Tampilan yang dipilih dari TVF yang ditunjukkan di atas. Dan, dalam situasi itu, SELECTakses tidak perlu diberikan ke TVF, hanya ke View, seperti yang ditunjukkan di bawah ini:

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

Dan sekarang untuk mengujinya:

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;

Untuk info lebih lanjut tentang Penandatanganan Modul, silakan kunjungi: https://ModuleSigning.Info/

Solomon Rutzky
sumber
Apakah sertifikat dicadangkan sebagai bagian dari cadangan reguler? Atau mereka disimpan di tempat lain dan memerlukan cadangan sistem file juga? Dan apa yang terjadi jika Anda mengembalikan ke lingkungan yang lebih rendah yang mungkin menggunakan kata sandi yang berbeda, dll.?
Chris Aldrich
@ChrisAldrich Dalam penggunaan yang ditunjukkan di sini, ini didukung dengan DB karena sepenuhnya disimpan dalam Database. Jika Anda menggunakan ALTER CERTIFICATE ... DROP PRIVATE KEYmaka kunci pribadi akan hilang jika Anda tidak terlebih dahulu mencadangkannya ke file menggunakan SERTIFIKAT CADANGAN . Namun, kunci publik masih ada sys.certificates. Dan kunci publik tidak perlu kata sandi. Hanya menggunakan kunci pribadi untuk menandatangani modul memerlukan kata sandi (yang sama di seluruh server, tidak seperti saat melindungi melalui kunci utama).
Solomon Rutzky