Güvenlik, Bilgi işlem dünyasında başlı başına bir öneme sahiptir. Mevzu veritabanı güvenliği konusuna gelince ise hayati bir önem taşır. Çünkü veritabanı içerisinde bulunduğu organizasyonun tüm verileri ve bilgileri yer almaktadır. Düşünün, e-ticaret işi yapan şirkette görev alıyorsunuz ve veritabanı içerisinde müşteri bilgileri, siparişleri, ödemeleri gibi çok sayıda bilgi yer alıyor. Bu bilgilerin ise güvenliğini takip etmek ve sağlamak ise DBA ’in – Veritabanı Yöneticisinin- en önemli görevlerinden bir tanesidir. İşte bu yazıda SQL Server 2016 ile kazanım sağladığımız ve sonraki sürümlerde yer alan güvenlik, şifreleme çözümlerinden bahsediyor olacağım. Unutmayın, burada ki özellikler aynı zamanda KVKK tarafında da bir noktada ihtiyacınız olacaktır. Makale içerisinde yer alan örnekleri kendiniz uygulamak isterseniz en az SQL Server 2017 sisteminizde kurulu olması gerekiyor. Ücretsiz versiyon olarak Developer edition tercih edebilirsiniz. Benim sistemimde SQL Server 2019 Developer edition kuruludur.
SQL Server Row Level Security Nedir?
Satır düzeyinde güvenlik, SQL Server ’da uzun süredir talep edilen bir özelliktir ve Microsoft SQL Server 2016 ile tanıtımını gerçekleştirdi. Bu özelliği SQL Server 2016 ve sonraki tüm versiyon ve sürümlerde (Express, Standart ve Enterprise) kullanabilirsiniz.
Row-Level Security (RLS) , bir çok müşteri için bir çok iş ihtiyacını karşılamaktadır. Dolayısıyla satır düzeyinde güvenlik hakkında birçok senaryo üretebiliriz. Birincisi, tüm müşterileriniz aynı tabloda olduğunda ve Satış sorumlusu kişilerin diğer müşterilerden gelen verileri görmeden bu tabloya göre rapor verebilmesi önemli bir ihtiyaçtır. Farklı bir örnek verecek olursak, bir hastane içerisinde bir hemşire düşünün. Bu hemşirenin sadece kendi hastalarına ait verileri görebilmesini, farklı hemşire üzerindeki verileri görmemesinin sağlanması ihtiyaç olabilir. Muhtemelen ben örnek verdikçe siz kendi uygulamalarınıza bunun nasıl uygulanacağını düşünerek senaryo üretiyorsunuzdur. Bu nedenle satır düzeyinde güvenlik – Row Level Security – tabloları yapılandırmanız olanak tanır. Böylece kullanıcılar sadece erişim izni verilmiş satırları görebilir. Normal şartlarda bu işlemi gerçekleştirmek için uygulama seviyesinde where koşulu ile işlem yapan kişiye göre sınırlama uygulamanız gerekirdi. Fakat Insert, Update ve Delete işlemlerini gerçekleştirirken sadece kendi sınırlaması içerisinde işlem yapmasını sağlamak hakkında farklı iş süreçleri üretmeniz gerekiyor olur. İşte burada SQL Server 2016 ile gelen Row Level Security – RLS – sizin için biçilmiş kaftandır.
SQL Server Row Level Security için Dipnot: Bu özellik, size oturum bazında bir güvenlik sağlayacaktır.
Yukarıda bahsettiğimiz örneklerimizden birkaçı hakkında bu özelliği nasıl kullanırız anlatalım.
Örnek 1: Bir mağaza çalışanısınız ve gün sonunda ne kadarlık satış yaptığınızı görmek istiyorsunuz.
Bu yazı için ben oluşturduğumuz “DMC_SQLSecurity” isimli veritabanı kullanıp örnek veriyor olacağım. Siz bunu kendi tarafınızda uygularken değiştirmeyi unutmayın.
Örnek içerisinde kullanmak için 1 Satış Yöneticisi, 2 tane Satış temsilcisi oluşturmam gerekiyor.
Use DMC_SQLSecurity go CREATE USER SatisYoneticisi WITHOUT LOGIN; CREATE USER SatisTemsilcisi1 WITHOUT LOGIN; CREATE USER SatisTemsilcisi2 WITHOUT LOGIN;
İhtiyacım olacak kullanıcılarımı oluşturdum. Şimdi sırada bir Satış tablosuna ihtiyacım var. Hemen aşağıdaki kod ile oluşturalım.
CREATE TABLE Satis ( Id int, SatisYapan sysname, Urun varchar(10), Adet int );
Satis tablosunu oluşturduktan sonra aşağıdaki kod ile kayıt ekleyelim.
INSERT INTO Satis VALUES (1, 'SatisTemsilcisi1', 'Notebook', 5), (2, 'SatisTemsilcisi1', 'PC', 2), (3, 'SatisTemsilcisi1', 'Monitor', 4), (4, 'SatisTemsilcisi2', 'Telefon', 2), (5, 'SatisTemsilcisi2', 'HDMI kablo', 5), (6, 'SatisTemsilcisi2', 'Sandalye', 5);
Kayıtların eklendiğini görelim.
SELECT * FROM Satis;
Resim-1
Oluşturduğumuz kullanıcılarımıza Satis tablosu üzerinde verileri görebilmeleri için “Select” yetkisi verelim.
GRANT SELECT ON Satis TO SatisYoneticisi; GRANT SELECT ON Satis TO SatisTemsilcisi1; GRANT SELECT ON Satis TO SatisTemsilcisi2; GO
Satis tablosu üzerinde sorgulama yaptığımızda bize her iki satış temsilcisi arkadaşımızın da verilerin geldiği gördük. Şimdi satış temsilcilerin sadece kendi satışlarını görebilmelerini sağlamak için SQL Server Row Level Security – RLS – özelliğini kullanacağız. Bunun için de bize bir adet True değer döndüren bir Inline Table Value Function ihtiyacımız var.
CREATE OR ALTER FUNCTION dbo.fn_RLS (@SatisYapan AS sysname) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT 1 AS fn_RLS_Sonucu WHERE @SatisYapan = USER_NAME() OR USER_NAME() = 'SatisYoneticisi'; GO
Bu işlemden sonra oluşturduğumuz Inline fonksiyonu filter edecek bir policy oluşturmamız gerekiyor.
CREATE SECURITY POLICY SatisFiltresi ADD FILTER PREDICATE dbo.fn_RLS(SatisYapan) ON dbo.Satis WITH (STATE = ON);
Oluşturduğumuz fonksiyon ve Policy kodlarını inceleyecek olursak; gördüğümüz üzere fonksiyonumuz parametre olarak kullanıcı adı alıyor ve geriye True ve NULL değerleri döndürüyor. POLICY bölümümüzde ise PRADICATE bölümünde oluşturduğumuz fn_RLS adında ki fonksiyonumuzu tablomuz üzerinde sorgu çalıştırıldığında otomatik olarak Filtrelemek için kullanılacağını ve hangi tablo üzerinde işlemi gerçekleştireceğini belirtiyoruz.
Şimdi bu tanımlamalar sonrasında Satis tablomuzu sorgulayalım.
-- SatisTemsilcisi1 ile satis tablosunu sorguluyoruz EXECUTE AS USER = 'SatisTemsilcisi1'; SELECT *,USER_NAME() USerName FROM Satis; REVERT; -- SatisTemsilcisi2 ile satis tablosunu sorguluyoruz EXECUTE AS USER = 'SatisTemsilcisi2'; SELECT *,USER_NAME() USerName FROM Satis; REVERT; -- SatisYoneticisi ile Satis tablosunu sorguluyoruz EXECUTE AS USER = 'SatisYoneticisi'; SELECT *,USER_NAME() USerName FROM Satis; REVERT;
Resim-2
Hatta öyle ki, bağlanıp işlemleri gerçekleştirdiğiniz kullanıcı ile Satis tablosunu sorgulamak isterseniz karşınıza kayıt gelmeyecekti.
SELECT * FROM Satis;
Resim-3
Peki Satis tablosu boş mu? Değil tabi ki, SatisYapan bilgisine uygun bir kullanıcı geldiğinde select sorgusunun sonucu dönüyor, aksi taktirde yazdığımız Inline fonksiyondan null değeri döndüğü için ekrana değer gelmiyor. Aklınıza hemen bu özelliği kullanmak adına SQL Server 2016 öncesi versiyonlarda nasıl uygulayacağız sorusu geliyorsa hemen onun da cevabını aşağıdaki örnek ile açıklayalım.
SQL Server 2016 öncesi Row Level Security nasıl Uygulanır?
Yukarıda Row Level Security kullanımı hakkında bir örnek gerçekleştirdik, şimdi aynı örnek konusu üzerinden SQL Server 2016 öncesinde nasıl bir kullanım yapabiliriz bunu anlatalım. Satis Temsilcilerimiz ve Satis yöneticilerimiz aynı olsun.
Örnek için çalışmaya başlamadan önce RLS örneğinde oluşturduğumuz Satis tablosunu drop edelim. Drop etmeden önce oluşturduğumuz policy off yapmamız gerekiyor.
DROP SECURITY POLICY [dbo].[SatisFiltresi] GO Drop Table Satis
Drop işlemini yaptık, şimdi örneğimiz için tekrar çalışmaya başlayabiliriz. Benzer örnek için yine Satis tablosu oluşturup içerisine örnek kayıtlar ekleyelim.
CREATE TABLE Satis ( Id int, SatisYapan sysname, Urun varchar(10), Adet int ); INSERT INTO Satis VALUES (1, 'SatisTemsilcisi1', 'Sunucu', 5), (2, 'SatisTemsilcisi1', 'MousePad', 2), (3, 'SatisTemsilcisi1', 'Mouse', 4), (4, 'SatisTemsilcisi2', 'Maske', 2), (5, 'SatisTemsilcisi2', 'Cüzdan', 5)
Satis tablosunu sorgulayalım.
SELECT * FROM Satis;
Resim-4
RLS özelliğini kullanamayacağımız için bir user mapping tablosuna ihtiyacımız var.
CREATE TABLE SQLUserMapping (CustomerID VARCHAR(5), SQLUserName sysname, Active Bit CONSTRAINT PK_SQLUserMapping PRIMARY KEY (CustomerID, SQLUserName)); GO
Mapping tablosuna kayıt ekleyelim.
INSERT INTO SQLUserMapping (CustomerID, SQLUserName, Active) VALUES ('DMC01', 'SatisTemsilcisi1', 1) GO
Şimdi Satis tablosu ile Mapping tablosunu eşleştirmesini yapacağımız ve satışları raporlayacağımız view oluşturalım.
CREATE OR ALTER VIEW v_Satis AS SELECT Satis.* FROM Satis JOIN SQLUserMapping on Satis.SatisYapan = SQLUserMapping.SQLUserName AND SQLUserMapping.SQLUserName = USER_NAME() GO
Daha önce tanımlamasını yaptığımız kullanıcılarımızı v_satis isimli view select edebilmeleri için yetkilerini veriyoruz.
GRANT SELECT ON v_Satis TO SatisYoneticisi; GRANT SELECT ON v_Satis TO SatisTemsilcisi1; GRANT SELECT ON v_Satis TO SatisTemsilcisi2;
Yetki tanımlamasını gerçekleştirdikten sonra SatisTemsilcisi1 kullanıcısı ile hem Satis tablosunu hem de v_satis isimli view sorgulayalım.
EXECUTE AS USER = 'SatisTemsilcisi1'; SELECT *,USER_NAME() USerName FROM satis; REVERT;
Resim-5
Yukarıdaki resimde gördüğümüz üzere kullanıcımızın Satis tablosunu görmeye yetkisi yok. Şimdi v_satis için sorgulama yapalım.
EXECUTE AS USER = 'SatisTemsilcisi1'; SELECT *,USER_NAME() USerName FROM v_Satis; REVERT;
Resim-6
SatisTemsilcisi2 ve SatisYoneticisi kullanıcılarımız ile v_satis sorgulayalım.
EXECUTE AS USER = 'SatisTemsilcisi2'; SELECT *,USER_NAME() USerName FROM v_Satis; REVERT;
Resim-7
EXECUTE AS USER = 'SatisYoneticisi'; SELECT *,USER_NAME() USerName FROM v_satis; REVERT;
Resim-8
Resim-7 ve Resim-8 de görüldüğü üzere sorgulama sonucu boş geldi, sebebi çünkü view içerisinde yaptığımız mapping tanımlamasıdır. Eğer ki SatisYoneticisi için view de değişiklik yaparsanız satistemsilcisi1 işlemleri görebilir.
CREATE OR ALTER VIEW v_satis AS SELECT Satis.* FROM Satis JOIN SQLUserMapping on Satis.SatisYapan = SQLUserMapping.SQLUserName AND SQLUserMapping.SQLUserName = USER_NAME() OR USER_NAME() = 'SatisYoneticisi' GO
Tekrar SatisYoneticisi ile sorguluyoruz.
EXECUTE AS USER = 'SatisYoneticisi'; SELECT *,USER_NAME() USerName FROM v_satis; REVERT;
Resim-9
SQL Server Row Level Security – RLS – hakkında detaylı bilgiyi yukarıda edindiniz. Bir sonraki yazımız SQL Server encryption – SQL Server da Şifreleme- konusunu anlatıyor olacağım.
#SQL #SQLServer #SQLServerSecurity #SQLRowLevelSecurity #SQLRLS #VeritabanıGuvenligi