동적 데이터 마스킹

적용 대상: SQL Server 2016(13.x) 이상 Azure SQL 데이터베이스Azure SQL Managed InstanceAzure Synapse Analytics

동적 데이터 마스킹 다이어그램입니다.

동적 데이터 마스킹(DDM)에서는 권한이 없는 사용자로 마스킹하여 중요한 데이터 노출을 제한합니다. 애플리케이션의 보안 설계 및 코딩을 크게 간소화하는 데 사용됩니다.

이 콘텐츠는 일반적으로 SQL Server와 관련된 동적 데이터 마스킹 개념에 적용됩니다. 다른 플랫폼과 관련된 콘텐츠를 사용할 수 있습니다.

동적 데이터 마스킹 개요

동적 데이터 마스킹을 사용하면 고객이 애플리케이션 계층에 미치는 영향을 최소화하고 표시할 중요한 데이터의 양을 지정할 수 있게 하여 중요한 데이터에 대한 무단 액세스를 방지할 수 있습니다. 지정된 데이터베이스 필드에 DDM을 구성하여 쿼리의 결과 집합에서 중요한 데이터를 숨길 수 있습니다. DDM을 사용하면 데이터베이스의 데이터가 변경되지 않습니다. 마스킹 규칙이 쿼리 결과에서 적용되므로 DDM은 기존 애플리케이션과 함께 사용하기 쉽습니다. 많은 애플리케이션에서 기존 쿼리를 수정하지 않고 중요한 데이터를 마스킹할 수 있습니다.

  • 중앙 데이터 마스킹 정책은 데이터베이스의 중요한 필드에서 직접 작동합니다.
  • 중요한 데이터에 액세스할 수 있는 권한 있는 사용자 또는 역할을 지정합니다.
  • DDM은 전체 마스킹 및 부분 마스킹 기능과 숫자 데이터에 대한 임의 마스크 기능을 갖추고 있습니다.
  • 간단한 Transact-SQL 명령에서 마스크를 정의하고 관리합니다.

동적 데이터 마스킹의 목적은 중요한 데이터의 노출을 제한하여 데이터에 대한 액세스 권한이 없는 사용자가 보지 못하게 하는 것이지 데이터베이스 사용자가 데이터베이스에 직접 연결하여 중요한 데이터 조각을 노출하는 과도한 쿼리를 실행하지 못하게 하는 것은 아닙니다. 동적 데이터 마스킹은 기타 SQL Server 보안 기능(감사, 암호화, 행 수준 보안 등)에 보완적이며 데이터베이스에서 중요한 데이터의 보호를 강화하려면 이러한 모든 기능을 사용하는 것이 좋습니다.

동적 데이터 마스킹은에서 SQL Server 2016(13.x) 및 Azure SQL Database에서 사용할 수 있으며 Transact-SQL 명령을 사용하여 구성됩니다.합니다. Azure Portal을 사용하여 동적 데이터 마스킹을 구성하는 방법에 대한 자세한 내용은 SQL 데이터베이스 동적 데이터 마스킹 시작하기(Azure Portal)을 참조하세요.

참고 항목

Microsoft Entra ID는 이전의 Azure AD(Azure Active Directory)입니다.

동적 데이터 마스크 정의

해당 열의 데이터를 난독 처리하기 위해 테이블의 열에 마스킹 규칙을 정의할 수 있습니다. 5가지 유형의 마스크를 사용할 수 있습니다.

함수 설명 예제
기본값 지정된 필드의 데이터 형식에 따라 전체 마스킹.

문자열 데이터 형식의 경우 필드의 크기가 4자 미만인 경우 XXXX 미만의 XXXX를 사용합니다(char, nchar, varchar, nvarchar, text, ntext).

숫자 데이터 형식(bigint, bit, decimal, int, money, numeric, smallint, smallmoney, tinyint, float, real)의 경우 0 값을 사용합니다.

날짜 및 시간 데이터 형식(date, datetime2, datetime, datetimeoffset, smalldatetime, time)의 경우 1900-01-01 00:00:00.0000000을 사용합니다.

이진 데이터 형식의 경우 단일 바이트의 ASCII 값 0을 사용합니다(binary, varbinary, image).
열 정의 구문 예제: Phone# varchar(12) MASKED WITH (FUNCTION = 'default()') NULL

변경 구문 예제: ALTER COLUMN Gender ADD MASKED WITH (FUNCTION = 'default()')
전자 메일 이메일 주소의 형식에서 이메일 주소의 첫 번째 문자와 상수 접미사 ".com"을 표시하는 마스킹 방법입니다. aXXX@XXXX.com. 정의 구문 예제: Email varchar(100) MASKED WITH (FUNCTION = 'email()') NULL

변경 구문 예제: ALTER COLUMN Email ADD MASKED WITH (FUNCTION = 'email()')
임의 지정된 범위 내에서 임의 값으로 원래 값을 마스킹하기 위해 숫자 유형에서 사용할 임의 마스킹 함수입니다. 정의 구문 예제: Account_Number bigint MASKED WITH (FUNCTION = 'random([start range], [end range])')

변경 구문 예제: ALTER COLUMN [Month] ADD MASKED WITH (FUNCTION = 'random(1, 12)')
사용자 지정 문자열 첫 번째 및 마지막 문자를 표시하고 가운데에 사용자 지정 안쪽 여백 문자열을 추가하는 마스킹 방법입니다. prefix,[padding],suffix

원래 값이 너무 짧아서 전체 마스크를 완료할 수 없는 경우 접두사 또는 접미사 부분이 표시되지 않습니다.
정의 구문 예제: FirstName varchar(100) MASKED WITH (FUNCTION = 'partial(prefix,[padding],suffix)') NULL

변경 구문 예제: ALTER COLUMN [Phone Number] ADD MASKED WITH (FUNCTION = 'partial(1,"XXXXXXX",0)')

이렇게 하면 555.123.1234와 같은 전화 번호가 5XXXXXXX로 바뀝니다.

추가 예제:

ALTER COLUMN [Phone Number] ADD MASKED WITH (FUNCTION = 'partial(5,"XXXXXXX",0)')

이렇게 하면 555.123.1234와 같은 전화 번호가 555.1XXXXXXX로 바뀝니다.
DateTime 적용 대상: SQL Server 2022(16.x)

데이터 형식 datetime, datetime2, date, time, datetimeoffset, smalldatetime으로 정의된 열에 대한 마스킹 메서드입니다. 하루 중 year => datetime("Y"), month=> datetime("M") , day=>datetime("D"), hour=>datetime("h"), minute=>datetime("m") 또는 seconds=>datetime("s") 일부를 마스킹하는 데 도움이 됩니다.
datetime 값의 연도를 마스킹하는 방법의 예:

ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("Y")')

datetime 값의 월을 마스킹하는 방법의 예:

ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("M")')

datetime 값의 분을 마스킹하는 방법의 예:

ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("m")')

사용 권한

테이블에 대한 SELECT 권한이 있는 사용자는 테이블 데이터를 볼 수 있습니다. 마스킹된 것으로 정의된 열에는 마스킹된 데이터가 표시됩니다. 마스킹이 정의된 열에서 마스킹되지 않은 데이터를 검색할 수 있도록 사용자에게 UNMASK 권한을 부여합니다.

관리자 및 역할은 ALTER ANY MASKUNMASK 권한을 모두 포함하는 CONTROL 권한을 통해 항상 마스크 해제된 데이터를 볼 수 있습니다. sysadmin, serveradmin 또는 db_owner 같은 관리자 또는 역할은 설계상 데이터베이스에 대한 CONTROL 권한을 가지며 마스킹되지 않은 데이터를 볼 수 있습니다.

동적 데이터 마스크로 테이블을 만드는 데 특별한 권한이 필요하지 않습니다. 구성표 권한에 대한 표준 CREATE TABLEALTER 만 필요합니다.

열 마스크를 추가, 대체 또는 제거하려면 테이블에서 ALTER ANY MASK 권한 및 ALTER 권한이 필요합니다. ALTER ANY MASK 를 보안 책임자에게 부여하는 것이 적합합니다.

참고 항목

UNMASK 권한은 메타데이터 표시에 영향을 주지 않습니다. UNMASK를 단독으로 부여하면 메타데이터가 공개되지 않습니다. UNMASK는 항상 SELECT 권한과 함께 적용되어야 합니다. 예를 들어 데이터베이스 범위에 UNMASK를 부여하고 개별 테이블에 SELECT를 부여하면 사용자는 선택할 수 있는 개별 테이블의 메타데이터만 볼 수 있고 다른 메타데이터는 볼 수 없습니다. 메타데이터 표시 유형 구성도 참조하세요.

최선의 구현 방법 및 일반적인 사용 사례

  • 열에서 마스크를 만들어도 해당 열에 대한 업데이트가 차단되지 않습니다. 따라서 사용자가 마스킹된 열을 쿼리할 때 마스킹된 데이터를 받더라도 동일 사용자에게 쓰기 권한이 있다면 데이터를 업데이트할 수 있습니다. 적절한 Access Control 정책을 사용하여 업데이트 권한을 제한해야 합니다.

  • 마스킹된 열에서 다른 테이블로 SELECT INTO 또는 INSERT INTO를 사용하여 데이터를 복사하면 대상 테이블에서 마스킹된 데이터가 생성됩니다(UNMASK 권한 없이 사용자가 내보낸 것으로 가정).

  • 동적 데이터 마스킹은 SQL Server 가져오기 및 내보내기 실행 시 적용됩니다. 마스킹된 열을 포함한 데이터베이스를 사용하면 마스킹된 데이터가 있는 내보내는 데이터 파일이 생성되며(UNMASK 권한이 없는 사용자가 내보낸다고 가정), 가져온 데이터베이스에는 정적으로 마스킹된 데이터가 포함됩니다.

마스크된 열에 대한 쿼리

sys.masked_columns 보기를 사용하여 마스킹 함수가 적용된 테이블 열을 쿼리합니다. 이 보기는 sys.columns 보기에서 상속됩니다. sys.columns 보기의 모든 열과 is_maskedmasking_function 열을 반환하여 열이 마스킹되는지, 그렇다면 정의된 마스킹 함수를 나타냅니다. 이 보기는 마스킹 함수가 적용된 열만 보여줍니다.

SELECT c.name, tbl.name as table_name, c.is_masked, c.masking_function
FROM sys.masked_columns AS c
JOIN sys.tables AS tbl
    ON c.[object_id] = tbl.[object_id]
WHERE is_masked = 1;

제한 사항

데이터베이스 수준에서 CONTROL SERVER 사용 권한이 있거나 CONTROL 권한이 있는 사용자는 원래 형식으로 마스킹된 데이터를 볼 수 있습니다. 여기에는 관리 사용자 또는 sysadmin, serveradmin, db_owner 등의 역할이 포함됩니다.

다음 열 형식에 대해 마스킹 규칙을 정의할 수 없습니다.

  • 암호화된 열(상시 암호화)

  • FILESTREAM

  • COLUMN_SET 또는 열 집합에 포함된 스파스 열

  • 계산 열에는 마스크를 구성할 수 없지만 계산 열이 마스크가 있는 열에 종속되는 경우 계산 열은 마스크된 데이터를 반환합니다.

  • 데이터 마스킹 열은 FULLTEXT 인덱스의 키가 될 수 없습니다.

  • PolyBase 외부 테이블의 열

UNMASK 권한이 없는 사용자의 경우, 사용되지 않은 READTEXT, UPDATETEXTWRITETEXT 문은 동적 데이터 마스킹용으로 구성된 열에서 제대로 작동하지 않습니다.

동적 데이터 마스크 추가는 기본 테이블에 대한 스키마 변경으로 구현되므로 종속성이 있는 열에서 수행할 수 없습니다. (예: 계산된 열에서 참조하는 열) 종속성이 있는 열에 대해 동적 데이터 마스크를 추가하려고 하면 오류 ALTER TABLE ALTER COLUMN _columnname_ failed because one or more objects access this column이 발생합니다. 이 제한을 해결하려면 먼저 종속성을 제거한 다음 동적 데이터 마스크를 추가하면 종속성을 다시 생성할 수 있습니다. 예를 들어 종속성이 해당 열에 종속된 인덱스 때문인 경우 인덱스를 삭제한 다음 마스크를 추가한 다음 종속 인덱스를 다시 생성할 수 있습니다.

데이터 마스킹 함수가 정의된 열을 참조하는 식을 프로젝션할 때마다 식도 마스킹됩니다. 참조된 열을 마스킹하는 데 사용되는 함수(기본값, 메일, 임의, 사용자 지정 문자열)와 관계없이 결과 식은 항상 기본 함수를 사용하여 마스킹됩니다.

두 개의 서로 다른 Azure SQL 데이터베이스 또는 여러 SQL Server 인스턴스에서 호스트된 데이터베이스에 걸친 데이터베이스 간 쿼리는 MASKED 열에서 모든 종류의 비교 또는 조인 작업을 포함할 경우 올바른 결과를 제공하지 않습니다. 원격 서버에서 반환된 결과는 이미 MASKED 형식이며 로컬에서 모든 종류의 비교 또는 조인 작업에 적합하지 않습니다.

참고 항목

기본 테이블이 인덱싱된 뷰에서 참조되는 경우 동적 데이터 마스킹은 지원되지 않습니다.

보안 정보: 유추 또는 무작위 기술을 사용하여 마스킹 무시

동적 데이터 마스킹은 애플리케이션에서 사용되는 미리 정의된 쿼리 집합에서 데이터 노출을 제한하여 애플리케이션 개발을 간소화하도록 설계되었습니다. 동적 데이터 마스킹은 프로덕션 데이터베이스에 직접 액세스하는 경우 중요한 데이터를 실수로 노출하지 않도록 하는 데 유용할 수 있지만, 임시 쿼리 권한이 있는 권한 없는 사용자가 기술을 사용하여 실제 데이터에 액세스할 수 있음을 알고 있어야 합니다. 이러한 임시 액세스 권한을 부여해야 하는 경우 모든 데이터베이스 작업을 모니터링하여 이 시나리오를 방지할 수 있도록 감사를 사용해야 합니다.

예를 들어 데이터베이스에서 임시 쿼리를 실행할 수 있는 충분한 권한이 있는 데이터베이스 보안 주체를 고려하고 기본 데이터를 '추측'하고 궁극적으로 실제 값의 유추를 시도합니다. [Employee].[Salary] 열에 마스크를 정의하고 이 사용자가 직접 데이터베이스에 연결하여 값 추측을 시작하면서 결국 Employees 테이블의 [Salary] 값을 유추한다고 가정해보겠습니다.

SELECT ID, Name, Salary FROM Employees
WHERE Salary > 99999 and Salary < 100001;
ID 속성 급여
62543 Jane Doe 0
91245 John Smith 0

이 경우 임시 쿼리를 실행하는 사용자로부터 중요한 데이터를 보호하기 위해 단독으로 동적 데이터 마스킹을 사용할 수 없음을 보여 줍니다. 실수로 중요한 데이터의 노출을 방지하는 데 적절하지만 악의적인 의도를 가지고 기본 데이터를 유추하는 상황은 보호되지 않습니다.

데이터베이스에 대한 권한을 제대로 관리하고 항상 필요한 최소 권한 원칙에 따르는 것이 중요합니다. 또한 데이터베이스에서 발생하는 모든 활동을 추적하기 위해 감사를 사용하도록 설정해야 합니다.

2022년 SQL Server에서 도입된 세분화된 권한

SQL Server 2022(16.x)부터 데이터베이스의 서로 다른 수준에서 권한이 없는 사용자에게 마스킹하여 중요한 데이터에 대한 무단 액세스를 방지하고 제어권을 얻을 수 있습니다. 데이터베이스 수준, 스키마 수준, 테이블 수준 또는 열 수준에서 사용자, 데이터베이스 역할, Microsoft Entra ID 또는 Microsoft Entra 그룹에 UNMASK 권한을 부여하거나 철회할 수 있습니다. 이 향상된 기능은 데이터베이스에 저장된 데이터에 대한 무단 액세스를 제어 및 제한하고 데이터 보안 관리를 개선하는 보다 세부적인 방법을 제공할 수 있습니다.

예제

동적 데이터 마스크 만들기

다음 예제에서는 세 가지 형식의 동적 데이터 마스크를 사용하여 테이블을 만듭니다. 이 예제에서는 테이블을 채우고 결과를 표시하도록 선택합니다.

-- schema to contain user tables
CREATE SCHEMA Data;
GO

-- table with masked columns
CREATE TABLE Data.Membership (
    MemberID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
    FirstName VARCHAR(100) MASKED WITH (FUNCTION = 'partial(1, "xxxxx", 1)') NULL,
    LastName VARCHAR(100) NOT NULL,
    Phone VARCHAR(12) MASKED WITH (FUNCTION = 'default()') NULL,
    Email VARCHAR(100) MASKED WITH (FUNCTION = 'email()') NOT NULL,
    DiscountCode SMALLINT MASKED WITH (FUNCTION = 'random(1, 100)') NULL
);

-- inserting sample data
INSERT INTO Data.Membership (FirstName, LastName, Phone, Email, DiscountCode)
VALUES
('Roberto', 'Tamburello', '555.123.4567', 'RTamburello@contoso.com', 10),
('Janice', 'Galvin', '555.123.4568', 'JGalvin@contoso.com.co', 5),
('Shakti', 'Menon', '555.123.4570', 'SMenon@contoso.net', 50),
('Zheng', 'Mu', '555.123.4569', 'ZMu@contoso.net', 40);
GO

새 사용자가 만들어지고 테이블이 있는 스키마에 대한 SELECT 권한이 부여됩니다. MaskingTestUser 보기로 마스킹된 데이터로 실행된 쿼리입니다.

CREATE USER MaskingTestUser WITHOUT LOGIN;

GRANT SELECT ON SCHEMA::Data TO MaskingTestUser;
  
-- impersonate for testing:
EXECUTE AS USER = 'MaskingTestUser';

SELECT * FROM Data.Membership;

REVERT;

결과는 다음에서 데이터를 변경하여 마스크를 보여 줍니다.

1 Roberto Tamburello 555.123.4567 RTamburello@contoso.com 10

변경 후:

1 Rxxxxxo Tamburello xxxx RXXX@XXXX.com 91

여기서 DiscountCode의 숫자는 모든 쿼리 결과에서 무작위로 표시됩니다.

기존 열에 대한 마스크 추가 또는 편집

ALTER TABLE 문을 사용하여 테이블의 기존 열에 마스크를 추가하거나 해당 열에서 마스크를 편집할 수 있습니다.
다음 예제에서는 LastName 열에 마스킹 함수를 추가합니다.

ALTER TABLE Data.Membership
ALTER COLUMN LastName ADD MASKED WITH (FUNCTION = 'partial(2,"xxxx",0)');

다음 예제에서는 LastName 열의 마스킹 함수를 변경합니다.

ALTER TABLE Data.Membership
ALTER COLUMN LastName VARCHAR(100) MASKED WITH (FUNCTION = 'default()');

마스크 해제된 데이터를 볼 수 있는 권한 부여

UNMASK 권한을 부여하면 MaskingTestUser 에서 마스크 해제된 데이터를 볼 수 있습니다.

GRANT UNMASK TO MaskingTestUser;

EXECUTE AS USER = 'MaskingTestUser';

SELECT * FROM Data.Membership;

REVERT;
  
-- Removing the UNMASK permission
REVOKE UNMASK TO MaskingTestUser;

동적 데이터 마스크 삭제

다음 문은 이전 예제에서 만든 LastName 열의 마스크를 삭제합니다.

ALTER TABLE Data.Membership
ALTER COLUMN LastName DROP MASKED;

세분화된 사용 권한 예제

  1. 사용자 테이블을 포함하는 스키마를 만듭니다.

    CREATE SCHEMA Data;
    GO
    
  2. 마스킹된 열을 사용하여 테이블을 만듭니다.

    CREATE TABLE Data.Membership (
        MemberID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
        FirstName VARCHAR(100) MASKED WITH (FUNCTION = 'partial(1, "xxxxx", 1)') NULL,
        LastName VARCHAR(100) NOT NULL,
        Phone VARCHAR(12) MASKED WITH (FUNCTION = 'default()') NULL,
        Email VARCHAR(100) MASKED WITH (FUNCTION = 'email()') NOT NULL,
        DiscountCode SMALLINT MASKED WITH (FUNCTION = 'random(1, 100)') NULL,
        BirthDay DATETIME MASKED WITH (FUNCTION = 'default()') NULL
    );
    
  3. 샘플 데이터를 삽입합니다.

    INSERT INTO Data.Membership (FirstName, LastName, Phone, Email, DiscountCode, BirthDay)
    VALUES
    ('Roberto', 'Tamburello', '555.123.4567', 'RTamburello@contoso.com', 10, '1985-01-25 03:25:05'),
    ('Janice', 'Galvin', '555.123.4568', 'JGalvin@contoso.com.co', 5, '1990-05-14 11:30:00'),
    ('Shakti', 'Menon', '555.123.4570', 'SMenon@contoso.net', 50, '2004-02-29 14:20:10'),
    ('Zheng', 'Mu', '555.123.4569', 'ZMu@contoso.net', 40, '1990-03-01 06:00:00');
    
  4. 서비스 테이블을 포함하는 스키마를 만듭니다.

    CREATE SCHEMA Service;
    GO
    
  5. 마스킹된 열을 사용하여 서비스 테이블을 만듭니다.

    CREATE TABLE Service.Feedback (
        MemberID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
        Feedback VARCHAR(100) MASKED WITH (FUNCTION = 'default()') NULL,
        Rating INT MASKED WITH (FUNCTION = 'default()'),
        Received_On DATETIME
        );
    
  6. 샘플 데이터를 삽입합니다.

    INSERT INTO Service.Feedback(Feedback, Rating, Received_On)
    VALUES
    ('Good', 4, '2022-01-25 11:25:05'),
    ('Excellent', 5, '2021-12-22 08:10:07'),
    ('Average', 3, '2021-09-15 09:00:00');
    
  7. 데이터베이스에 다른 사용자를 만듭니다.

    CREATE USER ServiceAttendant WITHOUT LOGIN;
    GO
    
    CREATE USER ServiceLead WITHOUT LOGIN;
    GO
    
    CREATE USER ServiceManager WITHOUT LOGIN;
    GO
    
    CREATE USER ServiceHead WITHOUT LOGIN;
    GO
    
  8. 데이터베이스의 사용자에게 읽기 권한을 부여합니다.

    ALTER ROLE db_datareader ADD MEMBER ServiceAttendant;
    
    ALTER ROLE db_datareader ADD MEMBER ServiceLead;
    
    ALTER ROLE db_datareader ADD MEMBER ServiceManager;
    
    ALTER ROLE db_datareader ADD MEMBER ServiceHead;
    
  9. 사용자에게 다른 UNMASK 권한을 부여합니다.

    --Grant column level UNMASK permission to ServiceAttendant
    GRANT UNMASK ON Data.Membership(FirstName) TO ServiceAttendant;
    
    -- Grant table level UNMASK permission to ServiceLead
    GRANT UNMASK ON Data.Membership TO ServiceLead;
    
    -- Grant schema level UNMASK permission to ServiceManager
    GRANT UNMASK ON SCHEMA::Data TO ServiceManager;
    GRANT UNMASK ON SCHEMA::Service TO ServiceManager;
    
    --Grant database level UNMASK permission to ServiceHead;
    GRANT UNMASK TO ServiceHead;
    
  10. ServiceAttendant 사용자 컨텍스트에서 데이터를 쿼리합니다.

    EXECUTE AS USER = 'ServiceAttendant';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  11. ServiceLead 사용자 컨텍스트에서 데이터를 쿼리합니다.

    EXECUTE AS USER = 'ServiceLead';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  12. ServiceManager 사용자 컨텍스트에서 데이터를 쿼리합니다.

    EXECUTE AS USER = 'ServiceManager';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  13. 사용자 ServiceHead 컨텍스트에서 데이터 쿼리

    EXECUTE AS USER = 'ServiceHead';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  14. UNMASK 권한을 철회하려면 다음 T-SQL 문을 사용합니다.

    REVOKE UNMASK ON Data.Membership(FirstName) FROM ServiceAttendant;
    
    REVOKE UNMASK ON Data.Membership FROM ServiceLead;
    
    REVOKE UNMASK ON SCHEMA::Data FROM ServiceManager;
    
    REVOKE UNMASK ON SCHEMA::Service FROM ServiceManager;
    
    REVOKE UNMASK FROM ServiceHead;