Supabase RLS 켜도 정책 없으면 데이터 전체 노출되는 실수 패턴과 점검 체크리스트

RLS를 켜놨는데도 데이터가 전부 보였어요. 이게 실제로 일어난 일이에요.
“RLS 켜면 안전하다"고 알고 계신 분 많죠? 그런데 켜는 것만으로는 부족해요. 정책(Policy)이 없으면 오히려 더 위험한 상황이 생기거든요. 실제 사고 패턴을 뜯어보고, 지금 당장 쓸 수 있는 점검 체크리스트를 정리해 드릴게요.
다룰 내용은 이래요:
- RLS 없을 때 vs 정책 없이 RLS만 켰을 때 어떤 차이가 있는지
- 실제 노출이 발생한 구체적인 실수 패턴
- 서비스 키(Service Role Key) 남용 문제
- 지금 바로 쓸 수 있는 RLS 점검 체크리스트
핵심 요약
- Supabase에서 RLS를 활성화해도 정책(Policy)을 하나도 추가하지 않으면, 기본 동작에 따라 모든 데이터 접근이 차단되거나 반대로 의도치 않은 전체 노출이 발생할 수 있어요.
- 가장 흔한 실수는
SELECT정책만 만들고INSERT/UPDATE/DELETE를 열어두거나,service_role키를 클라이언트에 노출하는 두 가지예요.- Supabase 공식 문서(2026년 기준)에 따르면, RLS 비활성화 상태의 테이블은 인증 여부와 상관없이
anon키로 전체 조회가 가능해요.- 서비스 키는 RLS를 우회하도록 설계된 키예요. 프론트엔드 코드에 단 한 번이라도 넣으면 안 돼요.
- 체계적인 정책 점검 없이 배포하면, MVP 단계에서 만든 “임시” 정책이 프로덕션에 그대로 남아 사고로 이어져요.
RLS가 뭔지부터 짚고 넘어갈게요
Supabase는 PostgreSQL 기반이에요. 그래서 PostgreSQL의 Row Level Security 기능을 그대로 써요. 테이블 안의 행(Row) 하나하나에 “누가 볼 수 있는지"를 정의하는 규칙이에요.
예를 들어볼게요. profiles 테이블이 있다고 하면, 기본 상태에서 anon 키로 접근하면 전체 행이 다 보여요. RLS를 활성화하면 “정책이 없는 행은 차단"이 기본값이 돼요. 여기서 많은 분들이 오해해요. “RLS 켜면 안전하다"고요.
그런데 이게 반은 맞고 반은 틀려요.
RLS를 켜고 USING (true) 조건의 정책을 만들면 다시 전체가 열려요. 의도한 거라면 괜찮지만, MVP 단계에서 “일단 테스트용으로” 만든 정책이 그대로 남아있는 경우가 문제예요. Supabase 공식 문서의 Troubleshooting 가이드에서도 이 패턴을 대표적인 실수로 명시하고 있어요.
타임라인을 보면 이래요:
- 2023-2024년: Supabase가 빠르게 성장하며 스타트업 도입 급증
- 2025년 하반기: 커뮤니티에서 “RLS 켰는데 데이터 다 보인다"는 사고 제보가 늘기 시작
- 2026년 현재: CodeScan 보안 블로그 기준, Supabase 관련 보안 리포트 중 RLS 미설정·오설정이 가장 많은 비중을 차지
2026년 기준으로 Supabase는 더 이상 “개발자용 실험 도구"가 아니에요. 실 서비스에 쓰는 팀이 압도적으로 많아졌고, 그만큼 실수의 파급이 커졌어요.
실제로 어떤 실수가 데이터를 노출시켰나
실수 #1: 정책 없이 RLS만 켠 경우
Supabase 대시보드에서 RLS 토글을 켜면, 그 테이블은 “정책 없음” 상태가 돼요. 이 상태의 기본 동작은 PostgreSQL 스펙에 따라 모든 접근 차단이에요.
문제는 여기서 시작돼요. “안 보이는 게 맞네” 하고 넘어간 뒤, 나중에 데이터가 필요해서 정책을 하나 추가해요. 이렇게요:
CREATE POLICY "allow_all"
ON profiles
FOR SELECT
USING (true);
이러면 모든 사용자가 모든 프로필을 볼 수 있어요. 빠른 테스트 목적으로 만든 정책이 배포 환경까지 따라가는 거예요.
실수 #2: service_role 키를 클라이언트에 사용
이게 가장 위험한 패턴이에요.
service_role 키는 RLS를 완전히 우회해요. 서버 사이드 작업(어드민 기능, 배치 처리)을 위해 설계된 키인데, 프론트엔드 .env 파일에 NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY로 올려두는 경우가 실제로 있어요.
NEXT_PUBLIC_ 접두사가 붙는 순간, 이 값은 브라우저에 그대로 노출돼요. 누구나 개발자 도구에서 꺼내 쓸 수 있고, RLS는 완전히 무력화되는 거예요.
실수 #3: 작업(Operation)별 정책 누락
RLS 정책은 SELECT, INSERT, UPDATE, DELETE를 각각 따로 설정해야 해요.
| 작업(Operation) | 정책 설정 여부 | 실제 동작 |
|---|---|---|
| SELECT | ✅ 설정 | 본인 행만 조회 |
| INSERT | ❌ 누락 | 누구든 삽입 가능 |
| UPDATE | ❌ 누락 | 누구든 수정 가능 |
| DELETE | ❌ 누락 | 누구든 삭제 가능 |
SELECT 정책만 꼼꼼히 만들고 나머지를 빠뜨리는 경우가 많아요. 조회는 막혔지만 쓰기는 열려있는 상태예요. 데이터 노출보다 데이터 오염이 더 빠르게 일어나요.
비교: RLS 설정 상태별 실제 동작
| 상태 | anon 키 접근 | authenticated 키 접근 | 위험도 |
|---|---|---|---|
| RLS 비활성화 | 전체 노출 | 전체 노출 | 🔴 매우 높음 |
| RLS 활성화 + 정책 없음 | 전체 차단 | 전체 차단 | 🟡 기능 안 됨 |
RLS 활성화 + USING (true) | 전체 노출 | 전체 노출 | 🔴 매우 높음 |
| RLS 활성화 + 올바른 정책 | 차단 | 본인 데이터만 | 🟢 정상 |
service_role 키 클라이언트 사용 | RLS 우회 전체 노출 | RLS 우회 전체 노출 | 🔴 치명적 |
지금 바로 쓰는 RLS 점검 체크리스트
아래 항목을 기준으로 점검하면 돼요.
테이블 단위 체크
- 모든 테이블에 RLS가 활성화되어 있는가?
-
USING (true)조건의 정책이 남아있지 않은가? - 각 테이블에 SELECT / INSERT / UPDATE / DELETE 정책이 모두 있는가?
정책 내용 체크
-
auth.uid()기반 행 수준 필터가 적용되어 있는가? - 정책 조건이 예상대로 작동하는지
EXPLAIN또는 Supabase 대시보드에서 확인했는가?
키 관리 체크
-
service_role키가 클라이언트 코드에 없는가? -
NEXT_PUBLIC_접두사로 시작하는 환경변수에 서비스 키가 없는가?
배포 전 체크
- 테스트용으로 만든 임시 정책이 삭제되었는가?
- 다른 사용자의
uid로 쿼리해서 본인 데이터만 나오는지 확인했는가?
이 중 하나라도 체크가 안 되면, 배포 전에 반드시 수정해야 해요.
앞으로 뭘 주시해야 할까요
- 4-8주 내: Supabase가 2026년 상반기 중 대시보드에 RLS 정책 경고 알림 기능을 롤아웃할 예정이에요. 정책이 없거나
USING (true)조건일 때 시각적 경고를 주는 방향으로요. - 3-6개월 내: 서드파티 보안 스캐너들이 Supabase 전용 RLS 감사 도구를 출시하기 시작할 가능성이 높아요. CodeScan 같은 곳이 이미 Supabase 전용 룰셋을 준비 중이에요.
- 지켜볼 질문 하나: Supabase가 기본값을 “RLS 활성화"로 바꿀까요? 지금은 테이블 생성 시 RLS가 꺼져 있어요. 이 기본값이 바뀌면 사고 건수가 크게 줄 거예요.
결국 핵심은 하나예요. RLS를 켰다는 사실보다 정책의 내용이 더 중요해요. 빠른 배포 압박 속에서 “일단 열어두고 나중에 수정"하는 정책이 사고의 씨앗이 돼요.
지금 운영 중인 서비스가 있다면, 위 체크리스트를 이번 주 안에 돌려보세요. 특히 service_role 키 검색은 5분이면 끝나요. 지금 바로 코드베이스에서 검색해 보세요.
참고자료
- [Supabase] 데이터베이스 테이블에 RLS 설정하기 – 모두의매뉴얼
- Supabase RLS 설정 실수 방지법 - CodeScan 보안 블로그
- Supabase Docs | Troubleshooting | RLS Simplified


