RLS가 무슨 뜻인가요? Supabase가 설정하라는 규칙
RLS는 로그인한 사용자가 테이블의 어떤 행을 읽고 추가·수정·삭제할 수 있는지 데이터베이스에서 검사하는 규칙이에요. 켜기만 하면 기본적으로 전부 막히므로 각 동작에 필요한 정책을 따로 만들어야 합니다.
핵심 요약
- RLS는 브라우저에서 Supabase Data API로 직접 접근하는 구조에서 행 단위 권한을 검사합니다.
- auth.uid()와 행의 사용자 ID를 비교해 본인 데이터만 허용하는 정책을 만들 수 있습니다.
- SELECT·INSERT·UPDATE·DELETE 정책을 각각 테스트하고 service role 키는 브라우저에 넣지 않습니다.
AI에게 Supabase를 연결해달라고 했더니 데이터 조회와 저장까지 구현해줍니다. 여기까지는 잘 된 것 같아요.
그런데 이어서 이런 말을 합니다.
테이블에 RLS를 활성화하고 로그인한 사용자가 자신의 데이터만 조회할 수 있도록 정책을 설정하세요.
로그인 기능도 만들었는데 보안 설정을 왜 또 해야 할까요? RLS를 켰더니 이번에는 데이터가 하나도 보이지 않기도 합니다.
RLS는 로그인한 사용자가 데이터베이스의 어떤 행을 읽고, 추가하고, 수정하고, 삭제할 수 있는지 정하는 규칙입니다. Supabase SDK로 브라우저에서 데이터베이스에 접근한다면 꼭 이해해야 하는 안전장치예요.
정책 설정에 들어가기 전에 단어의 의미부터 짧게 이해하고 싶다면 RLS 뜻과 행 단위 보안을 설명한 글을 먼저 읽어보세요. 이 글에서는 그 개념을 Supabase 정책에 실제로 적용하는 방법에 집중합니다.
이 글에서 설명하는 Supabase 연결 방식
Supabase 데이터베이스를 사용하는 방법은 하나만 있는 것이 아닙니다. 이 글에서는 바이브코딩 입문자가 자주 만나는 다음 구조를 설명합니다.
브라우저
→ Supabase SDK
→ Data API
→ PostgreSQL 데이터베이스
앱의 브라우저 코드에서 다음과 같이 데이터를 읽는 방식이에요.
const { data } = await supabase.from("todos").select("*");
서버에서 PostgreSQL에 직접 접속하는 구조는 권한을 검사하는 방식이 다릅니다. 두 구조의 차이는 Supabase를 연결하는 방법: 서버 접근을 추천하는 이유에서 이어서 설명합니다. 여기서는 브라우저에서 Supabase SDK를 사용하는 경우의 RLS에 집중할게요.
아직 데이터베이스와 스프레드시트 중 무엇을 선택해야 할지 고민하고 있다면 두 저장 방식의 차이부터 살펴봐도 좋아요.
로그인과 권한은 다릅니다. Supabase Auth는 요청을 보낸 사용자가 누구인지 알려주고, RLS는 그 사용자가 어떤 데이터에 접근할 수 있는지 검사해요. 로그인 기능을 만들었다고 사용자별 데이터 권한까지 자동으로 생기는 것은 아닙니다.
RLS는 행마다 출입 권한을 검사해요
RLS는 Row Level Security, 우리말로 행 단위 보안입니다.
할 일 앱의 todos 테이블에 여러 사용자의 데이터가 함께 저장되어 있다고 해볼게요.
| id | 할 일 | user_id |
|---|---|---|
| 1 | 장보기 | 민지의 ID |
| 2 | 보고서 작성 | 도윤의 ID |
민지가 로그인했다면 첫 번째 행만 보고 수정할 수 있어야 합니다. 이때 다음과 같은 RLS 조건을 사용할 수 있어요.
auth.uid() = user_id
auth.uid()는 현재 로그인한 사용자의 고유 ID를 뜻합니다. 이 값과 각 행의 user_id가 같을 때만 접근을 허용하는 거예요.
개념적으로는 모든 조회에 다음 조건이 자동으로 붙는 것과 비슷합니다.
SELECT *
FROM todos
WHERE user_id = 현재_로그인한_사용자_ID;
사용자가 요청할 때마다 프론트엔드에서 이 조건을 기억해 붙이는 것이 아니라, 데이터베이스가 정책을 강제로 적용한다는 점이 중요합니다.
RLS를 켰더니 데이터가 안 보이는 이유
RLS는 활성화만 하고 정책을 만들지 않으면 기본적으로 데이터를 허용하지 않습니다.
RLS 꺼짐
→ Data API 권한이 있는 역할에 데이터가 노출될 수 있음
RLS 켜짐 + 정책 없음
→ 아무 행에도 접근할 수 없음
RLS 켜짐 + 정책 있음
→ 정책이 허용한 행과 작업만 접근 가능
그래서 RLS를 켠 직후 목록이 빈 화면으로 나오는 것은 데이터가 삭제되었기 때문이 아닐 수 있어요. 현재 사용자에게 조회를 허용하는 정책이 없어서 데이터베이스가 빈 결과를 돌려준 것일 수 있습니다.
Supabase 대시보드의 Table Editor로 만든 테이블은 RLS가 기본으로 켜질 수 있지만, SQL로 직접 만든 테이블은 별도로 활성화해야 할 수 있어요. 테이블을 어떤 방식으로 만들었든 RLS가 켜졌는지와 필요한 정책이 있는지 둘 다 확인하는 편이 안전합니다.
조회·추가·수정·삭제 정책을 각각 확인하세요
RLS 정책은 CRUD 작업별로 나누어 생각해야 합니다.
| 작업 | 정책이 답해야 하는 질문 |
|---|---|
SELECT |
어떤 행을 볼 수 있나요? |
INSERT |
누구의 데이터로 새 행을 추가할 수 있나요? |
UPDATE |
어떤 기존 행을 어떻게 바꿀 수 있나요? |
DELETE |
어떤 행을 삭제할 수 있나요? |
조회 정책만 만들면 목록은 보이지만 새 할 일을 추가하지 못할 수 있습니다. 반대로 추가 정책은 있는데 조회 정책이 없다면 저장은 되었지만 화면에서 다시 읽지 못할 수 있어요.
정책에서는 두 종류의 조건을 자주 만납니다.
USING: 기존 행을 조회하거나 수정·삭제 대상으로 삼아도 되는지 검사합니다.WITH CHECK: 새로 추가하거나 수정한 행이 허용된 값인지 검사합니다.
예를 들어 사용자가 다른 사람의 ID를 넣어 할 일을 만들지 못하게 하려면 INSERT 정책에서 새 행의 user_id도 확인해야 합니다.
WITH CHECK (auth.uid() = user_id)
SQL 문법을 모두 외울 필요는 없습니다. 중요한 것은 “자신의 데이터만 볼 수 있다”는 한 문장만으로 끝내지 않고, 조회·추가·수정·삭제 각각에서 무엇을 허용할지 확인하는 습관이에요.
바이브코딩에서 자주 하는 RLS 실수
RLS만 켜고 정책을 만들지 않아요
모든 요청이 막혀 앱에 데이터가 하나도 보이지 않습니다. 보안을 끄는 대신 필요한 작업의 정책을 만들어야 해요.
SELECT 정책만 만들어요
목록은 보이지만 추가나 수정이 실패합니다. 화면에서 사용하는 CRUD 작업을 하나씩 확인해야 합니다.
테이블에 user_id가 없어요
각 행의 주인을 구분할 값이 없으면 “자신의 데이터만”이라는 정책을 만들기 어렵습니다. 사용자별 데이터에는 소유자를 나타내는 컬럼이 필요해요.
화면에서 보낸 user_id를 그대로 믿어요
사용자는 브라우저의 요청 값을 바꿀 수 있습니다. 새 행의 user_id가 실제 로그인한 사용자의 auth.uid()와 같은지 데이터베이스 정책에서도 확인해야 합니다.
수정한 행의 user_id를 다시 확인하지 않아요
기존 행에는 접근할 수 있더라도 수정 결과까지 허용된 값인지는 별도로 확인해야 합니다. UPDATE 정책의 WITH CHECK가 빠지면 다른 사용자의 ID로 소유자를 바꾸는 요청을 놓칠 수 있어요.
한 계정으로만 테스트해요
자기 데이터가 잘 보이는 것만 확인하면 다른 사용자의 데이터도 보이는지 알 수 없습니다. 최소 두 명의 계정을 만들어 서로의 데이터를 읽고 수정할 수 없는지 확인해야 해요.
AI에게 이렇게 요청해보세요
“RLS 설정해줘”라고만 말하면 AI가 앱의 권한을 추측해야 합니다. 테이블의 소유자와 허용할 작업을 구체적으로 알려주세요.
todos테이블에 RLS 정책을 만들어줘. 로그인한 사용자는user_id가 자신의auth.uid()와 같은 행만 조회·추가·수정·삭제할 수 있어야 해. SELECT, INSERT, UPDATE, DELETE 정책을 각각 만들고USING과WITH CHECK가 무엇을 검사하는지도 설명해줘. 아직 실제 데이터베이스에는 적용하지 말고 실행할 SQL을 먼저 보여줘.
정책을 적용한 뒤에는 테스트도 요청하세요.
사용자 A와 사용자 B를 만들어 RLS를 테스트해줘. 각자 자신의 할 일은 CRUD할 수 있어야 하고, 상대방의 할 일은 조회·수정·삭제할 수 없어야 해. 로그인하지 않은 사용자도 접근할 수 없어야 해. 실패하는 요청과 성공하는 요청을 표로 정리해줘.
AI가 만든 SQL을 전부 해석하지 못해도 괜찮습니다. 대신 다음 질문에는 답할 수 있어야 해요.
- 로그인하지 않은 사람은 무엇을 할 수 있나요?
- 로그인한 사용자는 어느 행을 볼 수 있나요?
- 다른 사람의
user_id로 데이터를 추가할 수 있나요? - 조회·추가·수정·삭제 정책이 모두 필요한가요?
- 두 명 이상의 사용자로 실제 권한을 테스트했나요?
정리
- 로그인 기능만으로 사용자별 데이터 권한이 자동으로 만들어지지는 않습니다.
- RLS는 로그인한 사용자의 정보와 각 행의 값을 비교해 접근을 허용하거나 막습니다.
- RLS를 켜고 정책을 만들지 않으면 기본적으로 데이터에 접근할 수 없습니다.
- SELECT, INSERT, UPDATE, DELETE에서 필요한 정책을 각각 확인해야 합니다.
- 두 명 이상의 테스트 사용자로 서로의 데이터에 접근할 수 없는지 검증해야 합니다.
RLS는 Supabase에 붙이는 복잡한 부가 설정이 아닙니다. 브라우저에서 Supabase Data API를 사용할 때 사용자마다 자기 데이터만 보이게 만드는 핵심 안전장치예요.
직접 Supabase를 연결하고 정책을 적용해보려면 바이브코딩 가이드 8장의 RLS 실습으로 이어가세요.
인스타그램 @ddukddak.build · 페이스북 뚝딱







