Stored Object Access Control

CREATE PROCEDURE 및 CREATE FUNCTION에는 CREATE ROUTINE 권한이 필요합니다.

DEFINER 절이 있는 경우 필요한 권한은 사용자(user) 값에 따라 다릅니다.

DEFINER 및 SQL SECURITY 절은 루틴(procedure or function, trigger, view) 실행 시에 액세스 권한을 확인할 때 사용할 보안 컨텍스트를 지정합니다.

 

저장 프로그램(프로시저, 함수, 트리거 및 이벤트) 및 뷰는 사용하기 전에 정의되며 참조 시 해당 권한을 결정하는 보안 컨텍스트 내에서 실행됩니다. 저장 객체의 실행에 적용 가능한 권한은 DEFINER 속성 및 SQL SECURITY 특성에 의해 제어됩니다.

  • The DEFINER Attribute
  • The SQL SECURITY Characteristic
  • Examples
  • Orphan Stored Objects
  • Risk-Minimization Guidelines

The DEFINER Attribute

저장 객체에는 MySQL 계정을 지정하는 DEFINER 속성을 포함할 수 있습니다. DEFINER 속성이 생략된 경우 객체 정의자는 객체를 만든 사용자입니다.
다음 규칙은 저장된 객체에 대한 DEFINER 속성으로 지정할 수 있는 계정을 결정합니다.

  • SET_USER_ID 권한(더 이상 사용되지 않는 SUPER 권한)이 있으면, 모든 계정을 DEFINER 속성으로 지정할 수 있습니다. 계정이 존재하지 않으면 경고가 뜹니다. 저장 객체 DEFINER 속성을 SYSTEM_USER 권한이 있는 계정으로 설정하려면 SYSTEM_USER 권한이 있어야 합니다.
  • 허용되는 계정은 CURRENT_USER()로 지정된 자신의 계정입니다. DEFINER를 다른 계정으로 설정할 수 없습니다.

존재하지 않는 DEFINER 계정으로 저장 객체를 생성하면 고아 객체가 생성되어 잘못된 결과를 초래할 수 있습니다.

 

The SQL SECURITY Characteristic

저장 루틴(프로시저 및 함수) 및 뷰의 경우 정의에는 개체가 정의자 컨텍스트에서 실행되는지 호출자 컨텍스트에서 실행되는지 지정하기 위해 DEFINER 또는 INVOKER 값이 있는 SQL SECURITY 특성이 포함될 수 있습니다. 정의에서 SQL SECURITY 특성을 생략하는 경우 기본값은 정의자(DEFINER) 컨텍스트입니다.

트리거 및 이벤트에는 SQL SECURITY 특성이 없으며 항상 정의자 컨텍스트에서 실행됩니다. 
정의자(DEFINER) 및 호출자(INVOKER) 보안 컨텍스트는 다음과 같은 차이가 있습니다.

  • 정의자 보안 컨텍스트에서 실행되는 저장된 객체는 DEFINER 속성으로 명명된 계정의 권한으로 실행됩니다. 이러한 권한은 호출하는 사용자의 권한과 완전히 다를 수 있습니다. 호출자는 개체를 참조할 수 있는 권한(예: 저장 프로시저를 호출하기 위한 EXECUTE 또는 뷰에서 선택하기 위한 SELECT)이 있어야 하지만 개체 실행 중에는 호출자의 권한이 무시되고 DEFINER 계정 권한만 중요합니다. DEFINER 계정에 권한이 거의 없는 경우 개체가 수행할 수 있는 작업이 이에 따라 제한됩니다. DEFINER 계정에 높은 권한이 있는 경우(예: 관리 계정) 개체는 누가 호출하든 상관없이 강력한 작업을 수행할 수 있습니다.
  • 호출자 보안 컨텍스트에서 실행되는 저장된 루틴 또는 뷰는 호출자에게 권한이 있는 작업만 수행할 수 있습니다. 

Examples

아래 프로시저는 정의자(DEFINER) 보안 컨텍스트에서 실행하기 위해 SQL SECURITY DEFINER로 선언된 프로시저입니다.

CREATE DEFINER = 'definer_user'@'%' PROCEDURE p1()
SQL SECURITY DEFINER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

p1 프로시저에 대한 EXECUTE 권한이 있는 모든 사용자는 CALL 문으로 호출할 수 있습니다. 그러나 p1이 실행될 때 정의자 보안 컨텍스트에서 실행되므로 DEFINER 속성으로 명명된 계정인 'admin'@'localhost'의 권한으로 실행됩니다. 이 계정 은 p1에 대한 EXECUTE 권한과 본문 내에서 참조되는 테이블 t1에 대한 UPDATE 권한이 있어야 합니다.

 

아래 프로시저는 SQL SECURITY 특성이 INVOKER라는 점을 제외하면 p1과 동일한 프로시저입니다.

CREATE DEFINER = 'definer_user'@'%' PROCEDURE p2()
SQL SECURITY INVOKER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

p1과 달리 p2는 호출자 보안 컨텍스트에서 실행되므로 DEFINER 속성 값에 관계없이 호출한 사용자의 권한으로 실행됩니다. 호출자에게 p2에 대한 EXECUTE 권한이나 테이블 t1에 대한 UPDATE 권한이 없으면 p2가 실패합니다.

 

예제1) DEFINER는 프로시저에 대한 EXECUTE와 테이블에 대한 SELECT 권한만 있고, INVOKER는 프로시저에 대한 EXECUTE와 테이블에 대한 SELECT, UPDATE 권한이 있을 경우 p2프로시져 INVOKER가 프로시저 수행하면 정상수행되지만 DEFINER 가 수행하면 권한 오류가 발생합니다.

CREATE DEFINER = 'definer_user'@'%' PROCEDURE p2()
SQL SECURITY INVOKER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

 

DEFINER가 프로시저를 수행했을 경우 UPDATE 권한이 없다는 오류가 발생합니다.

 

ERROR 1142 (42000): UPDATE command denied to user 'definer_user'@'localhost' for table 't1'

INVOKER가 프로시저를 수행했을 경우 프로시저가 정상적으로 수행됩니다.

Query OK, 2 rows affected (0.02 sec)

예제2) 이번에는 위 예제와 반대로 INVOKER는 프로시저에 대한 EXECUTE와 테이블에 대한 SELECT 권한만 있고, DEFINER는 프로시저에 대한 EXECUTE와 테이블에 대한 SELECT, UPDATE 권한이 있을 경우 p1프로시져 수행 시 DEFINER와 INVOKER는 정상 수행합니다. 프로시저를 정의한 DEFINER가 권한이 있기 때문입니다.

CREATE DEFINER = 'definer_user'@'%' PROCEDURE p1()
SQL SECURITY DEFINER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

 

DEFINER 또는 INVOKER 가 프로시저를 수행했을 경우 프로시저가 정상적으로 수행됩니다.

Query OK, 2 rows affected (0.02 sec)

[참고사항]

프로시저 수행 권한을 줄 때 주의합니다.

특정 프로시저에 권한을 줄 때는 

GRANT EXECUTE ON PROCEDURE 형식을 사용하고

GRANT EXECUTE ON PROCEDURE db_name.procdure_name TO 'user_name'@'%';

특정 DB의 전체 프로시저에 대한 수행 권한을 줄 때는

GRANT EXECUTE ON db_name.* TO user_name 형식으로 줍니다.

GRANT EXECUTE ON db_name.* TO 'user_name'@'%';

 

DEFINER=CURRENT_USER() 로 설정

DEFINER 절을 생략하면 기본 정의자는 CREATE PROCEDURE 또는 CREATE FUNCTION 문을 실행하는 사용자입니다. 이는 DEFINER = CURRENT_USER를 명시적으로 지정하는 것과 같습니다.

 

*** 테스트 스크립트 ***

-- definer 계정 생성 및 권한 설정
create user 'definer_user'@'%' identified by 'definer_user';
grant select, update on userdb.* to 'definer_user'@'%';
grant execute on userdb.* to 'definer_user'@'%';

-- invoker 계정 생성 및 권한 설정
create user 'invoker_user'@'%' identified by 'invoker_user';
grant select on userdb.* to 'invoker_user'@'%';
grant execute on userdb.* to 'invoker_user'@'%';

-- SQL SECURITY를 DEFINER로 설정
delimiter //
CREATE DEFINER = 'definer_user'@'%' PROCEDURE p1()
SQL SECURITY DEFINER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;
//

-- SQL SECURITY를 INVOKER로 설정
delimiter //
CREATE DEFINER = 'definer_user'@'%' PROCEDURE p2()
SQL SECURITY INVOKER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;
//


-- DEFINER를 current_user로 설정
delimiter //
CREATE DEFINER = current_user PROCEDURE p3()
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;
//

 

MySQL DEFINER 정의 관련 정보 조회

SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.EVENTS;
SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.ROUTINES;
SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.TRIGGERS;
SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.VIEWS;

 

 

프로시져 (Stored procedure) 권한 문장

CREATE
DEFINER = { user | CURRENT_USER } 
PROCEDURE sp_process_ranking()
SQL SECURITY { DEFINER | INVOKER }
BEGIN
  ...
  ...
END;

 

함수 (Stored function) 생성 문장

CREATE
DEFINER = { user | CURRENT_USER } 
FUNCTION fn_get_usercount() RETURN INT UNSIGNED
SQL SECURITY { DEFINER | INVOKER }
BEGIN
  ...
  ...
END;

 

뷰 권한 문장

CREATE or REPLACE
DEFINER = { user | CURRENT_USER } 
SQL SECURITY { DEFINER | INVOKER }
VIEW view_name
AS SELECT ...

 

+ Recent posts