SQL Server 행별 액세스


10

나는 구조화 된 테이블을 가지고있다 (간체)

Name, EMail, LastLoggedInAt

LastLoggdInAt 필드가 null이 아닌 데이터 (선택 쿼리를 통해) 만 볼 수 있어야하는 SQL Server (RemoteUser) 사용자가 있습니다.

내가 할 수있는 것 같아? 가능합니까?


행 수준 보안에 대한 온라인 설명서 항목은 다음과 같습니다. docs.microsoft.com/en-us/sql/relational-databases/security/…
David Browne-Microsoft

답변:


32

SQL Server 보안 모델을 사용하면 기본 테이블에 대한 액세스 권한을 부여하지 않고도 뷰에 대한 액세스 권한을 부여 할 수 있습니다.

예제 코드는 개념을 보여주는 좋은 방법이므로 LoginDetails테이블과 해당 뷰를 사용하여 다음을 고려하십시오 .

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

로그인과 사용자를 생성 한 다음 테이블 자체를 볼 수있는 권한없이 해당 사용자에게보기에서 행을 선택할 수있는 권한을 할당합니다.

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

CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;

GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;

이제 두 개의 테스트 행을 삽입합니다.

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

보안 모델을 테스트합니다. 첫 번째 SELECT명령문은보기에서 선택하기 때문에 성공하지만 두 번째 SELECT명령문은 사용자가 테이블에 직접 액세스 할 수 없으므로 실패합니다.

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetailsView;
╔ =========== ╦ ======================================= == ╗
║ 사용자 이름 ║ 이메일 주소 ║ LastLoggedInAt ║
╠ =========== ╬ ======================================= == ╣
║ 사용자 y ║ y@y.com ║ 2018-02-15 07 : 36 : 54.490 ║
╚ =========== ╩ ======================================= == ╝
SELECT *
FROM dbo.LoginDetails;

REVERT

뷰의 결과는 질문에 필요한 LastLoggedInAt값이 NULL인 행을 제외합니다 .

SELECT기본 테이블에 대한 두 번째 문은 오류를 반환합니다.

메시지 229, 수준 14, 상태 5, 줄 28
개체 'LoginDetails', 데이터베이스 'tempdb', 스키마 'dbo'에 대한 SELECT 권한이 거부되었습니다.

대청소:

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

또는 SQL Server 2016 이상을 사용하는 경우 행 수준 보안 조건자를 사용하여 특정 사용자가 NULL LastLoggedInAt값을 가진 행을 보지 못하게 할 수 있습니다.

먼저 테이블, 로그인, 해당 로그인 사용자를 작성하고 테이블에 대한 액세스 권한을 부여합니다.

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;

다음으로 몇 개의 샘플 행을 삽입합니다. 하나의 행은 null LastLoggedInAt이고 다른 하나는 해당 열에 대해 널이 아닌 값입니다.

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

여기에서는 함수 에 전달 된 @LastLoggedInAt@username변수 값에 따라 0 또는 1의 행을 반환하는 스키마 바운드 테이블 반환 함수를 만들고 있습니다. 이 함수는 필터 술어에 의해 사용되어 특정 사용자로부터 숨길 행을 제거합니다.

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

이것은 테이블 SELECT에 대해 실행 된 명령문 에서 행을 제거하는 보안 필터입니다 dbo.LoginDetails.

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

위의 필터 는 테이블 dbo.fn_LoginDetailsRemoteUserPredicateLastLoggedInAt열에 대한 각 행의 값과 함께 현재 사용자의 이름을 전달 하여 함수를 사용 dbo.LoginDetails합니다.

일반 사용자로 테이블을 쿼리하는 경우 :

SELECT *
FROM dbo.LoginDetails

우리는 모든 행을 본다 :

╔ =========== ╦ ======================================= == ╗
║ 사용자 이름 ║ 이메일 주소 ║ LastLoggedInAt ║
╠ =========== ╬ ======================================= == ╣
║ 사용자 x ║ x@y.com ║ NULL ║
y 사용자 y ║ y@y.com ║ 2018-02-15 13 : 53 : 42.577 ║
╚ =========== ╩ ======================================= == ╝

그러나 다음과 같이 테스트하면 RemoteUser:

EXECUTE AS LOGIN = 'RemoteUser';

SELECT *
FROM dbo.LoginDetails

REVERT

"유효한"행만 볼 수 있습니다 :

╔ =========== ╦ ======================================= == ╗
║ 사용자 이름 ║ 이메일 주소 ║ LastLoggedInAt ║
╠ =========== ╬ ======================================= == ╣
║ 사용자 y ║ y@y.com ║ 2018-02-15 13 : 42 : 02.023 ║
╚ =========== ╩ ======================================= == ╝

그리고 우리는 정리합니다 :

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

이러한 방식으로 함수를 테이블에 스키마 바인딩하면 먼저 필터 술어와 dbo.fn_LoginDetailsRemoteUserPredicate함수를 삭제하지 않고 테이블의 정의를 수정할 수 없습니다 .


훌륭한 답변-감사합니다! 이 두 가지 방법의 성능 영향은 무엇입니까? 우리는 함수를 사용할 때 웹앱이 최대 5 배 느리다는 것을 발견했습니다. View Method를 봐야합니다.
LiamB

행 레벨 보안 기능은 테이블에서 읽은 각 행마다 평가됩니다. 해당 테이블에 대한 액세스가 상당히 느려질 것으로 예상됩니다. 반면에보기는 LastLoggedInAt컬럼 에 유용한 인덱스를 작성한다고 가정 할 때 성능에 거의 영향을 미치지 않습니다.
Max Vernon

말이 되네요. 이제 뷰를보고 잘 작동하는 것 같습니다! 사용자가 기준과 일치하는 행에 대한 사용자 데이터 만 편집 할 수 있도록하려면 뷰에서 가능합니까?
LiamB

도움을 주셔서 감사합니다
LiamB

예,보기를 통해 행을 편집 할 수 있습니다
Max Vernon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.