PostgreSQL:SecurityContext
PostgreSQL에서 View와 Function은 누구의 권한으로 실행되는가에 따라 두 가지 보안 모드를 가진다.
SECURITY DEFINER
권한은 객체 소유자(owner)로 적용됨. 그래서 RLS 가 ❌ 우회됨.
SECURITY INVOKER
권한은 호출자(caller)로 적용됨. 그래서 RLS 가 ✅ 적용됨.
SECURITY DEFINER vs SECURITY INVOKER
| SECURITY DEFINER | SECURITY INVOKER | |
| 실행 권한 | 객체 소유자 (owner) | 호출자 (caller) |
| RLS 적용 | ❌ 우회됨 | ✅ 적용됨 |
| 권한 검사 | owner의 권한으로 통과 | 호출자가 해당 테이블 권한 필요 |
| 용도 | 권한 상승이 필요한 작업 | 일반적인 데이터 접근 |
| 비유 | Unix의 setuid | 일반 실행 |
View에서의 적용
View는 기본적으로 SECURITY DEFINER로 동작한다. PostgreSQL 15+에서 security_invoker 옵션이 추가되었다.
-- SECURITY DEFINER (기본값): owner 권한으로 실행, RLS 우회
CREATE VIEW my_view AS
SELECT * FROM my_table;
-- SECURITY INVOKER: 호출자 권한으로 실행, RLS 적용
CREATE VIEW my_view
WITH (security_invoker = true)
AS
SELECT * FROM my_table;
-- 기존 View 변경
ALTER VIEW my_view SET (security_invoker = true);
Function에서의 적용
Function은 기본적으로 SECURITY INVOKER로 동작한다. View와 기본값이 반대이므로 주의.
-- SECURITY INVOKER (기본값): 호출자 권한으로 실행
CREATE FUNCTION get_users()
RETURNS SETOF users
LANGUAGE sql
AS $$
SELECT * FROM users;
$$;
-- SECURITY DEFINER: 함수 소유자 권한으로 실행 (권한 상승)
CREATE FUNCTION admin_get_all_users()
RETURNS SETOF users
LANGUAGE sql
SECURITY DEFINER
AS $$
SELECT * FROM users;
$$;
| 객체 | 기본값 | 변경 방법 |
| View | SECURITY DEFINER | |
| Function | SECURITY INVOKER | |
| WARNING |
| View와 Function의 기본값이 서로 반대이다. View는 기본이 DEFINER, Function은 기본이 INVOKER. |
SECURITY DEFINER 사용 시 주의사항
SECURITY DEFINER는 권한 상승(privilege escalation)을 허용하므로 신중하게 사용해야 한다.
권장 사항:
-
search_path를 명시적으로 설정하여 schema injection 방지:
CREATE FUNCTION admin_action()
RETURNS void
LANGUAGE sql
SECURITY DEFINER
SET search_path = public
AS $$
-- ...
$$;
- 입력값 검증을 철저히 할 것 — 호출자가 owner 권한을 간접적으로 악용할 수 있음
- 가능하면 SECURITY INVOKER를 우선 사용하고, 꼭 필요한 경우에만 DEFINER를 사용
Supabase에서의 활용
Supabase는 RLS 기반 보안 모델을 사용하므로:
- View: 반드시
security_invoker = true를 설정해야 RLS가 적용됨 - Function (SECURITY DEFINER): RLS를 우회하는 "서비스 레벨" 작업에 활용 (예: 관리자 전용 함수, 트리거 내부 로직)
- Function (SECURITY INVOKER): 일반 사용자 대상 함수에 사용, RLS가 자연스럽게 적용됨
자세한 내용은 Supabase:Database:RLS 참고.