HooneyLog
© 2026 Seunghoon Shin. All rights reserved.
모든 게시글
Backend
2026. 3. 28.•
2

Supabase RLS 완벽 가이드: anon key가 털려도 내 DB가 안전한 이유

Seunghoon Shin
작성자 Seunghoon Shin풀스택 개발자

Supabase RLS 완벽 가이드: anon key가 털려도 내 DB가 안전한 이유

1. 문제의 배경: "내 환경변수가 털렸다고?"

많은 주니어 개발자가 하는 가장 큰 오해 중 하나는 "프론트엔드의 .env 파일에 적어둔 환경변수는 비밀이다"라는 생각입니다. 하지만 Next.js에서 NEXT_PUBLIC_ 접두사를 붙이는 순간, 그 값은 빌드 타임에 자바스크립트 코드 안에 평문으로 박혀버립니다.

사용자가 우리 사이트에 접속해 F12(개발자 도구)를 누르고 네트워크 탭만 봐도, Supabase와 통신할 때 사용하는 anon key는 아주 선명하게 노출됩니다. 즉, 전 세계 누구나 여러분의 DB API 주소와 키를 알 수 있다는 뜻입니다. 만약 아무런 조치도 하지 않았다면, 해커는 이 키를 이용해 여러분의 DB 데이터를 싹 지워버리거나 남의 비공개 글을 훔쳐볼 수 있습니다.

2. 해결 방안 탐색: DB 내부의 지문 인식기, RLS

우리는 두 가지 선택지에 직면합니다.

  1. 전통적인 백엔드 서버 구축: 모든 DB 요청을 중간 서버(NestJS 등)에서 검증합니다. 안전하지만 개발 속도가 느려집니다.
  2. RLS(Row Level Security) 활용: Supabase(PostgreSQL)가 제공하는 엔진 레벨의 보안 정책을 사용합니다. 백엔드 코드 없이도 DB가 스스로 "누가 이 데이터를 만질 수 있는지"를 판단하게 합니다.

Supabase의 철학을 100% 활용하면서도 보안을 챙기는 정석적인 방법은 바로 RLS를 활성화하는 것입니다.

3. 핵심 개념 및 아키텍처

RLS란 무엇인가?

RLS는 행 수준 보안(Row Level Security)의 약자로, 테이블 전체에 대한 권한이 아니라 데이터 한 줄(Row)마다 개별적인 보안 규칙을 적용하는 기술입니다.

  • 동작 원리: 사용자가 쿼리를 날리면, DB 엔진은 실행 전에 설정된 Policy(정책)를 확인합니다.
  • 인증 연동: Supabase Auth와 긴밀하게 연결되어 있어, 현재 로그인한 유저의 ID(auth.uid())를 기준으로 필터링을 수행합니다.

아파트 비유로 이해하기

  • 테이블 권한: 아파트 단지 정문 열쇠 (열쇠만 있으면 모든 집을 다 들어갈 수 있음 - 위험!)
  • RLS: 각 집 현관문의 지문 인식기 (단지 안에는 들어왔어도, 자기 집 지문이 있는 사람만 문을 열 수 있음 - 안전!)

4. 구현 및 실무 패턴

1) RLS 활성화하기

가장 먼저 해당 테이블의 RLS를 켜야 합니다. (기본적으로 꺼져 있으면 무법지대입니다.)

ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

2) 대표적인 보안 정책 패턴

패턴 A: 모든 유저가 읽을 수 있지만, 작성자만 수정 가능

블로그 포스트나 댓글 시스템에서 가장 흔히 쓰이는 방식입니다.

-- 1. 모두에게 읽기 권한 허용 CREATE POLICY "전체 읽기 허용" ON posts FOR SELECT USING (true); -- 2. 로그인한 작성자에게만 수정 권한 허용 CREATE POLICY "작성자만 수정 가능" ON posts FOR UPDATE USING (auth.uid() = author_id);

패턴 B: 본인 데이터만 생성 가능

남의 이름으로 글을 쓰는 것을 방지합니다.

CREATE POLICY "본인 글만 작성 가능" ON posts FOR INSERT WITH CHECK (auth.uid() = author_id);

3) 트러블슈팅: "분명 데이터가 있는데 안 보여요!"

RLS를 켜고 나서 데이터를 조회했는데 빈 배열([])이 온다면, 해당 유저에게 허용된 Policy가 하나도 없기 때문입니다. RLS는 "허용되지 않은 모든 것은 거부한다"는 원칙으로 동작하므로, 반드시 SELECT 정책을 명시적으로 추가해줘야 합니다.

5. 결과 및 Trade-off

  • 장점: 별도의 백엔드 서버 없이도 강력한 보안을 유지할 수 있으며, 개발 속도가 비약적으로 향상됩니다. 또한 DB 엔진 수준에서 작동하므로 보안 우회가 거의 불가능합니다.
  • 단점: 정책이 복잡해질수록 SQL 문법이 난해해질 수 있고, 수많은 정책이 얽히면 성능에 미세한 영향을 줄 수 있습니다. 하지만 일반적인 서비스 규모에서는 체감하기 어렵습니다.

6. 마치며

"API 키는 공개되어 있다. 그러니 보안은 DB 내부에서 챙긴다." 이것이 Supabase 환경에서의 올바른 보안 마인드셋입니다.

환경변수에 anon key를 넣는 것은 보안을 위해서가 아니라 관리를 위해서라는 점을 꼭 기억하세요. 진짜 보안은 여러분이 정성스럽게 작성한 RLS Policy 한 줄에서 시작됩니다. 지금 바로 여러분의 Supabase 대시보드에 들어가 RLS가 켜져 있는지 확인해 보세요!

← 이전 글Prisma ORM 완벽 가이드: 스키마 설계부터 실무 쿼리까지 총정리
다음 글 →NestJS 아키텍처 가이드: 3-Layer부터 CQRS까지 실무 패턴 총정리