Menerapkan keamanan Tingkat Baris

Selesai

Keamanan tingkat baris (RLS) tidak menggunakan enkripsi dan beroperasi di tingkat database untuk membatasi akses ke tabel dengan menggunakan kebijakan keamanan berdasarkan keanggotaan grup atau konteks otorisasi. Hal ini secara fungsional setara dengan klausul WHERE.

Kebijakan keamanan memanggil fungsi bernilai tabel sebaris untuk melindungi akses ke baris dalam tabel.

Bergantung pada atribut pengguna, predikat menentukan apakah pengguna tersebut memiliki akses ke informasi yang relevan. Saat Anda menjalankan kueri terhadap tabel, kebijakan keamanan menerapkan fungsi predikat. Bergantung pada persyaratan bisnis, RLS dapat menjadi sederhana seperti WHERE CustomerId = 29 atau menjadi rumit seperti yang diperlukan.

Ada dua jenis kebijakan keamanan yang didukung oleh keamanan tingkat baris:

  • Filter predikat - membatasi akses data yang melanggar predikat.

    Access Definisi
    SELECT Tidak dapat melihat baris yang difilter.
    UPDATE Tidak dapat memperbarui baris yang difilter.
    DELETE Tidak dapat menghapus baris yang difilter.
    INSERT Tidak berlaku.
  • Blokir predikat - batasi perubahan data yang melanggar predikat.

    Access Definisi
    SETELAH SISIPKAN Mencegah pengguna menyisipkan baris dengan nilai yang melanggar predikat.
    SETELAH PEMBARUAN Mencegah pengguna memperbarui baris ke nilai yang melanggar predikat.
    SEBELUM PEMBARUAN Mencegah pengguna memperbarui baris yang saat ini melanggar predikat.
    SEBELUM MENGHAPUS Memblokir operasi penghapusan jika baris melanggar predikat.

Karena kontrol akses dikonfigurasi dan diterapkan pada tingkat database, perubahan aplikasi minimal - jika ada. Selain itu, pengguna dapat langsung memiliki akses ke tabel dan dapat mengkueri data mereka sendiri.

Keamanan tingkat baris diterapkan dalam tiga langkah utama:

  1. Membuat pengguna atau grup yang ingin Anda isolasi aksesnya.
  2. Buat fungsi bernilai tabel sebaris yang memfilter hasil berdasarkan predikat yang ditentukan.
  3. Buat kebijakan keamanan untuk tabel, menetapkan fungsi yang dibuat sebelumnya.

Perintah T-SQL berikut menunjukkan cara menggunakan RLS dalam skenario di mana akses pengguna dipisahkan oleh penyewa:

-- Create supporting objects for this example
CREATE TABLE [Sales] (SalesID INT, 
    ProductID INT, 
    TenantName NVARCHAR(10), 
    OrderQtd INT, 
    UnitPrice MONEY)
GO

INSERT INTO [Sales]  VALUES (1, 3, 'Tenant1', 5, 10.00);
INSERT INTO [Sales]  VALUES (2, 4, 'Tenant1', 2, 57.00);
INSERT INTO [Sales]  VALUES (3, 7, 'Tenant1', 4, 23.00);
INSERT INTO [Sales]  VALUES (4, 2, 'Tenant2', 2, 91.00);
INSERT INTO [Sales]  VALUES (5, 9, 'Tenant3', 5, 80.00);
INSERT INTO [Sales]  VALUES (6, 1, 'Tenant3', 5, 35.00);
INSERT INTO [Sales]  VALUES (7, 3, 'Tenant4', 8, 11.00);

-- View all the rows in the table  
SELECT * FROM Sales;

Berikutnya, buat pengguna dan beri mereka akses ke tabel Penjualan. Dalam contoh ini, setiap pengguna bertanggung jawab atas penyewa tertentu. Pengguna TenantAdmin memiliki akses untuk melihat data dari semua penyewa.

CREATE USER [TenantAdmin] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant1] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant2] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant3] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant4] WITH PASSWORD = '<strong password>'
GO

GRANT SELECT ON [Sales] TO [TenantAdmin]
GO
GRANT SELECT ON [Sales] TO [Tenant1]
GO
GRANT SELECT ON [Sales] TO [Tenant2]
GO
GRANT SELECT ON [Sales] TO [Tenant3]
GO
GRANT SELECT ON [Sales] TO [Tenant4]
GO

Selanjutnya, kita membuat skema baru, fungsi bernilai tabel sebaris, dan memberikan akses pengguna ke fungsi baru. Predikat WHERE @TenantName = USER_NAME() OR USER_NAME() = 'TenantAdmin' mengevaluasi apakah nama pengguna yang menjalankan kueri cocok dengan nilai kolom TenantName.

CREATE SCHEMA sec;  
GO  

--Create the filter predicate

CREATE FUNCTION sec.tvf_SecurityPredicatebyTenant(@TenantName AS NVARCHAR(10))  
    RETURNS TABLE  
WITH SCHEMABINDING  
AS  
    RETURN	SELECT 1 AS result
			WHERE @TenantName = USER_NAME() OR USER_NAME() = 'TenantAdmin';  
GO

--Grant users access to inline table-valued function

GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [TenantAdmin]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant1]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant2]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant3]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant4]
GO

--Create security policy and add the filter predicate
CREATE SECURITY POLICY sec.SalesPolicy  
ADD FILTER PREDICATE sec.tvf_SecurityPredicatebyTenant(TenantName) ON [dbo].[Sales]
WITH (STATE = ON);  
GO

Pada titik ini, kita siap untuk menguji akses:

EXECUTE AS USER = 'TenantAdmin';  
SELECT * FROM dbo.Sales;
REVERT;  
  
EXECUTE AS USER = 'Tenant1';  
SELECT * FROM dbo.Sales;
REVERT;  
  
EXECUTE AS USER = 'Tenant2';  
SELECT * FROM dbo.Sales;
REVERT;

EXECUTE AS USER = 'Tenant3';  
SELECT * FROM dbo.Sales;
REVERT;

EXECUTE AS USER = 'Tenant4';  
SELECT * FROM dbo.Sales;
REVERT;

Pengguna TenantAdmin akan melihat semua baris. Pengguna Tenant1, Tenant2, Tenant3, dan Tenant4 hanya boleh melihat baris mereka sendiri.

Jika Anda mengubah kebijakan keamanan dengan WITH (STATE = OFF);, Anda melihat bahwa pengguna melihat semua baris.

Cuplikan layar perintah T-SQL untuk mengubah kebijakan keamanan.

Catatan

Ada risiko kebocoran informasi jika penyerang membuat kueri dengan menambahkan klausa WHERE yang dirancang khusus dan, sebagai contoh, kesalahan membagi-dengan-nol, untuk memaksa pengecualian jika WHERE kondisinya benar. Ini dikenal sebagai serangan saluran samping. Bijaksana untuk membatasi kemampuan pengguna menjalankan kueri yang tidak direncanakan saat menggunakan keamanan tingkat baris.

Gunakan huruf besar

Keamanan tingkat baris sangat ideal untuk banyak skenario, termasuk:

  • Saat Anda perlu mengisolasi akses departemen di tingkat baris.
  • Saat Anda perlu membatasi akses data pelanggan hanya ke data yang relevan dengan perusahaan mereka.
  • Saat Anda perlu membatasi akses untuk tujuan kepatuhan.

Praktik terbaik

Berikut adalah beberapa praktik terbaik yang perlu dipertimbangkan saat menerapkan RLS:

  • Buat skema terpisah untuk fungsi predikat, dan kebijakan keamanan.
  • Hindari konversi jenis dalam fungsi predikat.
  • Hindari menggunakan gabungan tabel dan rekursi yang berlebihan dalam fungsi predikat.