SQL Server Satır Satır Erişimi


10

Bu şekilde yapılandırılmış bir tablo var (Basitleştirilmiş)

Name, EMail, LastLoggedInAt

LastLoggdInAt alan null değil sadece verileri (bir seçme sorgusu aracılığıyla) görebilmesi gerekir SQL Server (RemoteUser) bir kullanıcı var.

Bunu yapabilirim gibi mi? Mümkün mü?


Satır Seviyesi Güvenliği için Kitaplar Çevrimiçi konusu: docs.microsoft.com/en-us/sql/relational-databases/security/…
David Browne - Microsoft

Yanıtlar:


32

SQL Server güvenlik modeli, temel tablolara erişim izni vermeden bir görünüme erişim izni vermenizi sağlar.

Örnek kod bir kavramı göstermek için harika bir yol olduğundan, LoginDetailstablo ve karşılık gelen görünümle aşağıdakileri göz önünde bulundurun :

CREATE TABLE dbo.LoginDetails
(
    Username nvarchar(100) NOT NULL
    , EmailAddress nvarchar(256) NOT NULL
    , LastLoggedInAt datetime NULL
);
GO

CREATE VIEW dbo.LoginDetailsView
AS
SELECT ld.Username
    , ld.EmailAddress
    , ld.LastLoggedInAt
FROM dbo.LoginDetails ld
WHERE ld.LastLoggedInAt IS NOT NULL;
GO

Bir giriş ve bir kullanıcı oluşturacağız, ardından bu kullanıcıya, tablonun kendisini görüntüleme hakları olmadan görünümden satır seçme hakları atayacağız.

CREATE LOGIN RemoteUser 
WITH PASSWORD = '2q1345lkjsadfgsa0(*';

CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;

GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;

Şimdi iki test satırı ekleyeceğiz:

INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
    , ('user y', 'y@y.com', GETDATE());

Bu, güvenlik modelini test eder. İlk SELECTifade, görünümden seçtiği için başarılı olurken, ikinci SELECTtablo, kullanıcının tabloya doğrudan erişimi olmadığından başarısız olur.

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Kullanıcı Adı ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ kullanıcı y ║ y@y.com ║ 2018-02-15 07: 36: 54.490 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;

REVERT

Görünümdeki sonuçların , sorunuzun gerektirdiği şekilde LastLoggedInAtdeğerin olduğu satırı hariç tuttuğunu NULLunutmayın.

SELECTTemel tabloya karşı ikinci ifade bir hata döndürür:

Msg 229, Seviye 14, Durum 5, Satır 28
'LoginDetails', 'tempdb' veritabanı, 'dbo' şeması nesnesinde SELECT izni reddedildi.

Temizlemek:

DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;

Alternatif olarak, SQL Server 2016 veya daha yeni bir sürümünüz varsa, belirli kullanıcıların NULL LastLoggedInAtdeğerine sahip satırları görmesini engellemek için satır düzeyinde güvenlik tahmini kullanabilirsiniz .

İlk olarak, tabloyu, bir girişi, o giriş için bir kullanıcı yaratırız ve tabloya erişim veririz:

CREATE TABLE dbo.LoginDetails
(
    Username nvarchar(100) NOT NULL
    , EmailAddress nvarchar(256) NOT NULL
    , LastLoggedInAt datetime NULL
);
GO

CREATE LOGIN RemoteUser 
WITH PASSWORD = '2q1345lkjsadfgsa0(*';

CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;

GRANT SELECT ON dbo.LoginDetails TO RemoteUser;

Ardından, birkaç örnek satır ekliyoruz. Bir satırda null LastLoggedInAtve bir satırda null olmayan değer.

INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
    , ('user y', 'y@y.com', GETDATE());

Burada, işleve iletilen değişkenlere @LastLoggedInAtve @usernamedeğişkenlere bağlı olarak 0 veya 1 ile bir satır döndüren şemaya bağlı tablo değerli bir işlev oluşturuyoruz. Bu işlev, belirli kullanıcılardan gizlemek istediğimiz satırları ortadan kaldırmak için bir filtre tahmini tarafından kullanılır.

CREATE FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate
(
    @LastLoggedInAt datetime
    , @username sysname
)  
RETURNS TABLE  
WITH SCHEMABINDING  
AS  
    RETURN SELECT 1 AS fn_securitypredicate_result   
    WHERE (@username = N'RemoteUser' AND @LastLoggedInAt IS NOT NULL)
        OR @username <> N'RemoteUser';  
GO

Bu, tabloya SELECTkarşı çalıştırılan ifadelerden satırları ortadan kaldıran güvenlik filtresidir dbo.LoginDetails:

CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);

Yukarıdaki filtre , tablodaki sütun dbo.fn_LoginDetailsRemoteUserPredicateiçin her satırdaki değerlerle birlikte geçerli kullanıcının adını ileterek işlevi kullanır .LastLoggedInAtdbo.LoginDetails

Tabloyu normal kullanıcı olarak sorgularsak:

SELECT *
FROM dbo.LoginDetails

tüm satırları görüyoruz:

╔══════════╦══════════════╦═══════════════════════ ══╗
║ Kullanıcı Adı ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ kullanıcı x ║ x@y.com ║ NULL ║
║ kullanıcı y ║ y@y.com ║ 2018-02-15 13: 53: 42.577 ║
╚══════════╩══════════════╩═══════════════════════ ══╝

Ancak, şu şekilde test edersek RemoteUser:

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetails

REVERT

yalnızca "geçerli" satırlar görüyoruz:

╔══════════╦══════════════╦═══════════════════════ ══╗
║ Kullanıcı Adı ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ kullanıcı y ║ y@y.com ║ 2018-02-15 13: 42: 02.023 ║
╚══════════╩══════════════╩═══════════════════════ ══╝

Ve temizliyoruz:

DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;

Şema bağlamanın bir işlevi bu şekilde tabloya bağlamanın, önce filtre yüklemini ve dbo.fn_LoginDetailsRemoteUserPredicateişlevi düşürmeden tablonun tanımını değiştirmeyi imkansız hale getirdiğini unutmayın .


Mükemmel cevap - teşekkürler! Bu 2 yöntemin performans anlamı nedir. İşlevi kullandığımızda web uygulamamızın 5 kata kadar daha yavaş olduğunu tespit ettik. Görünüm Yöntemine bakmanız gerekiyor.
LiamB

Satır düzeyinde güvenlik işlevi, tablodan okunan her satır için değerlendirilir; Bu tabloya erişimi önemli ölçüde yavaşlatmasını beklerdim. Öte yandan görünüm, LastLoggedInAtsütun üzerinde yararlı bir dizin oluşturduğunuzu varsayarak performans üzerinde önemsiz bir etkiye sahip olmalıdır .
Max Vernon

Bu mantıklı - şimdi manzaraya bakacağım, iyi çalışıyor gibi görünüyor! Kullanıcının yalnızca bu ölçütlere uyan kullanıcı verilerini yalnızca görünümle düzenleyebilmesini istiyorsak, bu görünümle mümkün olabilir mi?
LiamB

Güzel, tüm çalışıyor - bu yardım için teşekkürler
LiamB

Evet, satırları görünümden düzenleyebilirsiniz
Max Vernon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.