본문 바로가기
문서Supabase 테이블에 RLS가 꺼져 있어요

Supabase 테이블에 RLS가 꺼져 있어요

데이터베이스 테이블을 만들었지만 "누가 볼 수 있는지" 잠금장치(RLS)를 안 켜서, 사실상 누구나 모든 사람의 데이터를 가져갈 수 있는 상태예요.

한눈에
위험도
높음(High)
CWE
CWE-862 · 권한 확인 누락
OWASP
A01:2021
vg-supabase-rls-disabled

이게 무슨 말이냐 (쉽게)

Supabase는 기본적으로 API 주소만 알면 테이블에 접근할 수 있게 열려 있어요. 그 문을 잠그는 게 RLS(Row Level Security, 행 단위 보안)입니다. RLS를 켜고 "본인 데이터만 볼 수 있다"는 규칙(정책)을 만들어야, 비로소 남의 데이터가 가려져요.

RLS를 안 켜면? 앱 화면에는 내 정보만 보이지만, 브라우저 개발자도구나 간단한 요청 한 줄이면 전체 회원 테이블이 통째로 나옵니다. 화면에서 안 보이는 것과, 서버가 안 주는 것은 완전히 다른 얘기예요.

실제로 어떻게 터지나 (시나리오)

당신이 만든 SaaS에 회원 1,000명이 가입했어요. profiles 테이블에 이메일·이름·결제 잔액이 들어있죠. RLS는 안 켰고요.

누군가 당신 사이트를 브라우저에서 열고 → 개발자도구 Network 탭을 봅니다 → Supabase 주소와 anon key(앱에 그대로 박혀 있음)를 복사 → 터미널에서 그 주소로 select * 한 번. 끝. 1,000명 전체 이메일·잔액이 JSON으로 쏟아집니다. 해킹 도구도, 비밀번호도 필요 없어요. anon key는 원래 공개되는 키라서, 잠금은 오로지 RLS뿐이거든요.

최악의 경우

나한테 해당되나? (체크)

→ 2개 이상 체크되면 거의 확실히 해당됩니다. 아래대로 고치세요.

어떻게 고치나 (복붙)

각 테이블마다 ① RLS를 켜고 ② "본인 것만" 정책을 추가합니다. Supabase SQL Editor에 붙여넣고 테이블명만 바꾸세요.

-- 1) 잠금장치 켜기 (테이블마다)
alter table public.profiles enable row level security;

-- 2) 읽기: 본인 행만
create policy "본인 프로필만 조회"
on public.profiles for select
using ( auth.uid() = id );

-- 3) 수정: 본인 행만
create policy "본인 프로필만 수정"
on public.profiles for update
using ( auth.uid() = id );

-- 4) 입력: 본인 id로만
create policy "본인 프로필만 생성"
on public.profiles for insert
with check ( auth.uid() = id );
테이블의 소유자 컬럼이 id가 아니라 user_id라면 auth.uid() = user_id로 바꾸세요.
관리자만 접근해야 하는 작업은 클라이언트에서 하지 말고, 서버(서비스 롤)에서 처리하세요.

고친 뒤 확인

  1. 01

    대시보드에서 잠금 표시 보기

    Supabase 대시보드 → Table editor에서 테이블에 RLS enabled 표시가 켜져 있는지 확인.

  2. 02

    로그아웃 상태로 불러보기

    anon key로 select * from profiles 호출 → 빈 결과(또는 거부)가 나와야 정상.

  3. 03

    로그인 상태로 불러보기

    로그인 사용자로는 본인 행만 나오는지 확인.

규제 연결

이 한 건이 곧 개인정보보호법(PIPA) 안전조치 의무 위반이에요. 관련 조항은 ISMS-P 2.6(접근통제)·PIPA 제29조(안전조치의무)입니다. 다만 리포트가 조항을 자동으로 붙여 주지는 않습니다 — 신뢰 센터의 참고 대조표에서 직접 보실 수 있습니다.

출처/더 읽기: Supabase RLS 공식 문서, OWASP A01:2021(Broken Access Control), Wiz Research(Moltbook), CVE-2025-48757. 이 카드는 우리가 직접 작성했습니다.

문서 목록으로