Supabase에서의 RLS(Row-Level Security)
Supabase를 쓰다 보면 반드시 마주치게 되는 개념 중 하나가 바로 RLS(Row-Level Security)입니다.
이 글에서는 RLS가 무엇이고, 왜 필요한지, Supabase에서는 어떻게 설정하고 활용하는지를 정리했습니다.
RLS란 무엇인가?
RLS(Row-Level Security)는 테이블의 각 행(row)에 대해 접근 권한을 제어하는 보안 기능입니다. PostgreSQL의 고급 기능 중 하나로, Supabase는 이 기능을 적극 활용해 사용자 단위 데이터 보호를 제공합니다.
예를 들어, 사용자가 자신의 할 일 목록만 조회할 수 있게 하려면 어떻게 해야 할까요?
전통적인 백엔드라면 쿼리마다 user_id 조건을 직접 걸어줘야겠지만, RLS를 활용하면 DB 레벨에서 정책(policy)을 설정해서 자동으로 필터링할 수 있습니다.
RLS가 없으면 생기는 문제
// 로그인된 유저가 아니라도 전체 todos를 다 조회할 수 있음
const { data } = await supabase.from('todos').select('*');
이런 코드가 있다면 모든 유저의 데이터가 노출될 수 있습니다.
Supabase에서의 RLS 활용
Supabase는 로그인한 사용자의 ID를 auth.uid()로 제공합니다. 이를 활용해 RLS 정책을 구성할 수 있습니다.
1. RLS 활성화
alter table todos enable row level security;
2. 행 단위 접근 정책(policy) 추가
create policy "Users can view own todos"
on todos for select
using (auth.uid() = user_id);
3. 삽입/수정 권한 제어도 가능
create policy "Users can insert their own todos"
on todos for insert
with check (auth.uid() = user_id);
프론트엔드에서는 어떻게 달라질까?
RLS 정책이 적용되면, 프론트엔드에서 다음처럼 단순한 쿼리를 날려도 안전합니다.
const { data } = await supabase.from('todos').select('*');
이제는 이 쿼리가 자동으로 로그인한 사용자에 해당하는 데이터만 반환합니다.
RLS는 Supabase에만 있는 개념일까?
아닙니다. RLS는 PostgreSQL의 기본 기능입니다. Supabase는 이를 래핑(wrapping)해서 더 쉽게 다룰 수 있도록 콘솔 UI와 API에서 제공할 뿐입니다.
구분 | 설명 |
Supabase | PostgreSQL 기반, auth.uid() 제공, RLS 정책 쉽게 구성 가능 |
PostgreSQL | 원래 RLS 기능이 존재, 직접 SQL로 구성 필요 |
Supabase에서 RLS를 강조하는 이유
Supabase는 PostgreSQL 기반이기 때문에, PostgreSQL의 RLS 기능을 그대로 활용할 수 있습니다. 특히 BaaS 백엔드에서 클라이언트가 직접 쿼리를 날리는 구조이다 보니, RLS 없이 보안사고가 발생할 가능성이 높습니다. 그래서 RLS가 보안 핵심 기능으로 강조되는 것입니다.
요약
- RLS는 사용자마다 다른 행(row)에 접근하도록 제한하는 데이터 보안 기능입니다.
- Supabase에서는 auth.uid()를 통해 로그인 사용자의 ID를 받아 정책을 구성할 수 있습니다.
- 프론트엔드에서는 단순한 쿼리만 작성해도 자동으로 보안이 적용되어 편리하고 안전합니다.