SQL Server Row by Row Access


10

Tôi có một bảng có cấu trúc như vậy (Đơn giản hóa)

Name, EMail, LastLoggedInAt

Tôi có một người dùng trong SQL Server (RemoteUser) chỉ có thể xem dữ liệu (Thông qua một truy vấn chọn) trong đó trường LastLoggdInAt không phải là null.

Có vẻ như tôi có thể làm điều này? Có thể không?


Đây là chủ đề Sách trực tuyến về Bảo mật cấp hàng: docs.microsoft.com/en-us/sql/relational-database/security/ trộm
David Browne - Microsoft

Câu trả lời:


32

Mô hình bảo mật SQL Server cho phép bạn cấp quyền truy cập vào chế độ xem mà không cấp quyền truy cập vào các bảng bên dưới.

Vì mã ví dụ là một cách tuyệt vời để hiển thị một khái niệm, hãy xem xét các điều sau đây, với một LoginDetailsbảng và chế độ xem tương ứng:

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

Chúng tôi sẽ tạo thông tin đăng nhập và người dùng, sau đó gán cho người dùng quyền đó để chọn các hàng từ chế độ xem mà không có bất kỳ quyền nào để xem chính bảng đó.

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

CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;

GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;

Bây giờ, chúng tôi sẽ chèn hai hàng thử nghiệm:

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

Điều này kiểm tra mô hình bảo mật. Câu SELECTlệnh đầu tiên thành công, vì nó đang chọn từ khung nhìn, trong khi SELECTcâu lệnh thứ hai không thành công vì người dùng không có quyền truy cập trực tiếp vào bảng.

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗
Tên người dùng EmailAddress LastLoggedInAt
╠══════════╬══════════════╬═══════════════════════ ══╣
Người dùng y ║ y@y.com 2018-02-15 07: 36: 54.490
╚══════════╩══════════════╩═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;

REVERT

Lưu ý các kết quả từ chế độ xem loại trừ hàng có LastLoggedInAtgiá trị NULL, như được yêu cầu trong câu hỏi của bạn.

Câu SELECTlệnh thứ hai đối với bảng bên dưới trả về lỗi:

Msg 229, Cấp 14, Trạng thái 5, Dòng 28
Quyền CHỌN đã bị từ chối trên đối tượng 'LoginDetails', cơ sở dữ liệu 'tempdb', lược đồ 'dbo'.

Dọn dẹp:

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

Cách khác, nếu bạn có SQL Server 2016 hoặc mới hơn, bạn có thể sử dụng một vị từ bảo mật cấp hàng để ngăn người dùng nhất định nhìn thấy các hàng có LastLoggedInAtgiá trị NULL .

Đầu tiên, chúng tôi tạo bảng, đăng nhập, người dùng cho thông tin đăng nhập đó và chúng tôi cấp quyền truy cập vào bảng:

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;

Tiếp theo, chúng tôi chèn một vài hàng mẫu. Một hàng có giá trị null LastLoggedInAtvà một hàng có giá trị khác null cho cột đó.

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

Ở đây, chúng ta đang tạo một hàm có giá trị bảng ràng buộc lược đồ trả về một hàng có 0 hoặc 1 tùy thuộc vào giá trị của các biến @LastLoggedInAt@usernamecác biến được truyền vào hàm. Hàm này sẽ được sử dụng bởi một vị từ bộ lọc để loại bỏ các hàng chúng ta muốn ẩn khỏi một số người dùng nhất định.

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

Đây là bộ lọc bảo mật giúp loại bỏ các hàng khỏi các SELECTcâu lệnh chạy trên dbo.LoginDetailsbảng:

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

Bộ lọc ở trên sử dụng dbo.fn_LoginDetailsRemoteUserPredicatehàm bằng cách chuyển tên của người dùng hiện tại, cùng với các giá trị từ mỗi hàng cho LastLoggedInAtcột từ dbo.LoginDetailsbảng.

Nếu chúng ta truy vấn bảng như một người dùng bình thường:

SELECT *
FROM dbo.LoginDetails

chúng tôi thấy tất cả các hàng:

╔══════════╦══════════════╦═══════════════════════ ══╗
Tên người dùng EmailAddress LastLoggedInAt
╠══════════╬══════════════╬═══════════════════════ ══╣
║ người dùng x ║ x@y.com NULL
Người dùng y ║ y@y.com 2018-02-15 13: 53: 42.577
╚══════════╩══════════════╩═══════════════════════ ══╝

Tuy nhiên, nếu chúng tôi kiểm tra như RemoteUser:

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetails

REVERT

chúng tôi chỉ thấy các hàng "hợp lệ":

╔══════════╦══════════════╦═══════════════════════ ══╗
Tên người dùng EmailAddress LastLoggedInAt
╠══════════╬══════════════╬═══════════════════════ ══╣
Người dùng y ║ y@y.com 2018-02-15 13: 42: 02.023
╚══════════╩══════════════╩═══════════════════════ ══╝

Và, chúng tôi dọn dẹp:

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

Xin lưu ý rằng lược đồ liên kết một hàm với bảng theo cách này sẽ không thể sửa đổi định nghĩa của bảng mà không bỏ qua biến vị ngữ bộ lọc và dbo.fn_LoginDetailsRemoteUserPredicatehàm.


Câu trả lời rực rỡ - cảm ơn! Ý nghĩa hiệu suất của 2 phương pháp này là gì. Chúng tôi đã phát hiện ra rằng ứng dụng web của chúng tôi chậm hơn tới 5 lần khi chúng tôi sử dụng chức năng này. Cần nhìn vào Phương pháp xem.
LiamB

Hàm bảo mật cấp hàng được ước tính cho mỗi và mọi hàng được đọc từ bảng; Tôi hy vọng nó sẽ truy cập chậm vào bảng đó. Mặt khác, chế độ xem sẽ có tác động không đáng kể đến hiệu suất khi giả sử bạn tạo một chỉ mục hữu ích trên LastLoggedInAtcột.
Max Vernon

Điều đó có ý nghĩa - tôi sẽ nhìn vào khung cảnh bây giờ, dường như đang hoạt động tốt! Nếu chúng tôi muốn người dùng chỉ có thể chỉnh sửa dữ liệu người dùng cho các hàng này phù hợp với tiêu chí có thể có với chế độ xem?
LiamB

Nó thật đẹp, tất cả đều hoạt động - cảm ơn vì sự giúp đỡ này
LiamB

Có, bạn có thể chỉnh sửa các hàng qua chế độ xem
Max Vernon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.