컨텍스트 전환 이해

실행 컨텍스트는 세션에 연결된 사용자나 로그인에 의해 결정되거나 모듈을 실행(호출)하여 결정됩니다. 실행 컨텍스트는 문 실행 권한 또는 동작 수행 권한이 있는 ID를 설정합니다. SQL Server에서 실행 컨텍스트는 EXECUTE AS 문을 실행하거나 모듈에 EXECUTE AS 절을 지정하여 다른 사용자 또는 로그인으로 전환될 수 있습니다. 컨텍스트가 전환된 후 SQL Server에서는 EXECUTE AS 문 또는 모듈을 호출하는 사용자 대신 해당 계정에 대한 로그인 및 사용자의 권한을 확인합니다. 데이터베이스 사용자 또는 SQL Server 로그인은 세션 또는 모듈이 실행되는 남은 시간 동안이나 컨텍스트 전환이 명시적으로 되돌려질 때까지 가장됩니다. 실행 컨텍스트에 대한 자세한 내용은 실행 컨텍스트 이해를 참조하십시오.

명시적 컨텍스트 전환

세션 또는 모듈의 실행 컨텍스트는 EXECUTE AS 문에 사용자 또는 로그인 이름을 지정하여 명시적으로 변경될 수 있습니다. 다음 이벤트 중 하나가 발생하기 전까지 가장이 계속 유지됩니다.

  • 세션이 삭제됩니다.

  • 컨텍스트가 다른 로그인 또는 사용자로 전환됩니다.

  • 컨텍스트는 이전 실행 컨텍스트로 되돌려집니다.

EXECUTE AS를 사용하여 다른 사용자를 명시적으로 가장하는 것은 SQL Server 이전 버전의 SETUSER와 비슷합니다. 자세한 내용은 EXECUTE AS와 SETUSER를 참조하십시오.

명시적 서버 수준 컨텍스트 전환

서버 수준에서 실행 컨텍스트를 전환하려면 EXECUTE AS LOGIN = 'login_name' 문을 사용하십시오. 로그인 이름은 sys.server_principals의 보안 주체로 표시되어야 하며 문 호출자에 지정한 로그인 이름에 대한 IMPERSONATE 권한이 있어야 합니다.

실행 컨텍스트가 서버 수준일 때 가장의 범위는 다음과 같습니다.

  • login_name에 대한 로그인 토큰은 SQL Server 인스턴스에 의해 인증되고 해당 인스턴스에서 유효합니다.

  • login_name의 서버 수준 권한 및 역할 멤버 자격이 인식됩니다.

REVERT 문을 사용하여 이전 컨텍스트로 돌아갑니다. REVERT 문의 호출자는 가장이 발생한 같은 데이터베이스에 있어야 합니다.

다음 예에서 Adventure Works Cycles의 네트워크 관리자인 Peter Connelly는 신입 사원인 Jinghao Liuhas의 SQL Server 로그인 계정을 만들려고 합니다. Peter의 SQL Server 로그인에는 SQL Server 로그인을 만드는 데 필요한 서버 수준 권한이 없지만 필요한 서버 수준 권한을 가진 SQL Server 로그인인 adventure-works\dan1에 대한 IMPERSONATE 권한이 있습니다. Peter가 SQL Server에 연결하면 세션에 대한 실행 컨텍스트는 Peter의 SQL Server 로그인에서 파생됩니다. SQL Server 로그인을 만들기 위해 Peter는 adventure-works\dan1의 실행 컨텍스트를 일시적으로 가정한 다음 로그인을 만듭니다. 마지막으로 Peter는 가정된 사용 권한을 포기합니다.

-- Switch execution context to the adventure-works\dan1 login account.
EXECUTE AS LOGIN = 'adventure-works\dan1';
-- Create the new login account.
CREATE LOGIN Jinghao1 WITH PASSWORD = '3KHJ6dhx(0xVYsdf';
-- Revert to the previous execution context.
REVERT;

명시적 데이터베이스 수준 컨텍스트 전환

데이터베이스 수준에서 컨텍스트를 전환하려면 EXECUTE AS USER = 'user_name' 문을 사용하십시오. 사용자 이름은 sys.database_principals의 보안 주체로 존재해야 하고 문 호출자는 지정한 사용자 이름에 대한 IMPERSONATE 권한이 있어야 합니다.

실행 컨텍스트가 데이터베이스 수준일 때 가장의 범위는 다음과 같습니다.

  • user_name에 대한 사용자 토큰은 SQL Server의 인스턴스에 의해 인증되고 현재 데이터베이스에서 유효합니다. 현재 데이터베이스의 범위에서 사용자 가장을 확장하는 방법은 EXECUTE AS를 사용하여 데이터베이스 가장 확장을 참조하십시오.

  • 현재 데이터베이스에 대한 user_name의 데이터베이스 수준 권한 및 역할 멤버 자격이 인식됩니다. 사용자 토큰 또는 역할 멤버 자격을 통해 ID에 명시적으로 부여된 서버 수준 권한이 인식되지 않습니다.

REVERT 문을 사용하여 이전 컨텍스트로 돌아갑니다. REVERT 문의 호출자는 가장이 발생한 같은 데이터베이스에 있어야 합니다.

다음 예에서 Adventure Works Cycles의 데이터베이스 관리자인 François Ajenstat는 AdventureWorksDW 데이터베이스에 대해 DBCC CHECKDB 문을 실행하려고 하지만 이 작업을 수행할 데이터베이스 수준 권한이 없습니다. 그러나 필요한 권한을 가진 계정인 dan1 사용자에 대한 IMPERSONATE 권한이 있습니다.

François가 AdventureWorksDW 데이터베이스에 연결하면 실행 컨텍스트가 François의 사용자 보안 토큰에 매핑됩니다. user token의 주 보안 주체 및 보조 보안 주체에 대해 문을 실행할 권한을 확인합니다. DBCC CHECKDB 문을 실행하는 데 필요한 권한이 없으므로 다음 문을 실행합니다.

-- EXECUTE AS USER = 'dan1';
-- Create a table in dan1's default schema
CREATE TABLE t_NewTable( data nvarchar(100) );
go
-- Revert to the previous execution context.
REVERT
go;

암시적 컨텍스트 전환

저장 프로시저, 트리거, 큐 또는 사용자 정의 함수와 같은 모듈의 실행 컨텍스트는 모듈 정의에 EXECUTE AS 절의 사용자 또는 로그인 이름을 지정하여 암시적으로 변경될 수 있습니다.

모듈이 실행되는 컨텍스트를 지정해서 SQL Server 사용자 계정을 제어하면 모듈에서 참조하는 개체에 대한 권한을 검사할 수 있습니다. 이렇게 하면 사용자 정의 모듈 및 해당 모듈에서 참조하는 개체 사이에 있는 개체 체인에서 좀 더 유연하게 권한 관리를 제어할 수 있습니다. 참조된 개체에 대한 명시적 사용 권한을 부여하지 않아도 모듈 자체에 대한 사용 권한을 사용자에게 부여할 수 있습니다. 모듈이 가장 중인 사용자에게만 모듈에서 액세스한 개체에 대한 사용 권한이 있어야 합니다.

가장의 수준은 가장이 정의된 모듈의 유형에 의해 결정됩니다.

서버 수준 가장은 다음 항목에서 정의될 수 있습니다.

  • DDL 트리거

서버 수준 가장의 범위는 "명시적 서버 수준 컨텍스트 전환"에서 이전에 정의된 범위와 같습니다.

데이터베이스 수준 가장은 다음 항목에서 정의될 수 있습니다.

  • DML 트리거

  • 저장 프로시저

  • 사용자 정의 함수

  • 데이터베이스 수준 가장의 범위는 "명시적 데이터베이스 수준 컨텍스트 전환"에서 이전에 정의된 범위와 같습니다.

  • 암시적 컨텍스트 전환에 대한 자세한 내용은 모듈에서 EXECUTE AS 사용을 참조하십시오.

다음 예에서 Mary는 MyTable 테이블의 소유자입니다. Mary는 사용자 Scott가 테이블을 자를 수 있기를 원하지만 Scott에게 테이블에 대한 직접적인 사용 권한이 없습니다. 따라서 Mary는 dbo.usp_TruncateMyTable 저장 프로시저를 만들고 Scott에게 이 프로시저에 대한 EXECUTE 권한을 부여합니다. Scott이 저장 프로시저를 실행하면 데이터베이스 엔진에서 해당 권한을 확인하여 Mary가 저장 프로시저를 실행하고 있을 때와 동일하게 테이블을 자를 수 있습니다. 테이블 소유자가 Mary이기 때문에 Scott에게 테이블 자체에 대한 직접적인 권한이 없더라도 문이 성공적으로 실행됩니다.

CREATE PROCEDURE dbo.usp_TruncateMyTable
WITH EXECUTE AS SELF
AS TRUNCATE TABLE MyDB..MyTable;