Supabase는 데이터베이스, 인증, 파일 저장소, API를 한곳에서 사용할 수 있어 빠르게 웹앱을 만들 때 유용합니다.
특히 AI 개발 도구와 함께 사용하면 백엔드를 처음 다루는 사람도 회원가입, 문의폼, 예약 기능을 비교적 빠르게 구현할 수 있습니다.
하지만 기능이 동작하는 것과 안전하게 운영할 수 있는 것은 다른 문제입니다.
Supabase 자체가 위험한 것은 아닙니다. 대부분의 문제는 API 키, 권한, Storage, 인증 설정을 정확히 이해하지 못한 상태에서 배포할 때 발생합니다.
이번 글에서는 Supabase로 웹앱을 만들 때 자주 하는 실수 10가지를 정리해보겠습니다.
Supabase 프로젝트를 프론트엔드에 연결하면 API 키가 브라우저 코드나 네트워크 요청에서 보일 수 있습니다.
처음 발견하면 키가 유출됐다고 생각하기 쉽지만, Supabase의 publishable key는 웹과 모바일 앱에서 공개되는 것을 전제로 만들어진 키입니다. 기존 프로젝트의 anon key도 같은 용도로 사용됩니다.
중요한 것은 키가 보이느냐가 아니라 그 키로 어떤 데이터에 접근할 수 있느냐입니다.
publishable key 또는 기존 anon key만 사용했는가anon, authenticated 역할에 필요한 권한만 허용했는가공개용 키는 숨기는 것보다 권한을 제한하는 것이 핵심입니다.
secret key와 기존 service_role key는 공개용 키와 다릅니다.
이 키들은 높은 권한을 가지며 RLS를 우회할 수 있으므로, 브라우저나 모바일 앱에 포함되면 안 됩니다.
환경변수에 넣었다고 모두 비밀이 되는 것도 아닙니다. 프론트엔드 빌드에 포함되는 공개 환경변수는 최종 JavaScript 파일에서 확인될 수 있습니다.
sb_secret_... 형식의 Secret keyservice_role key이 값들은 서버, Edge Function 또는 접근이 통제된 백엔드에서만 사용해야 합니다.
프로젝트 전체에서 다음 문자열을 검색합니다.
service_role
sb_secret_
DATABASE_URL
DB_PASSWORD
JWT_SECRET
Git 저장소에 커밋된 적이 있다면 코드에서 지우는 것만으로 끝나지 않습니다. 해당 키를 교체하고 커밋 기록과 배포 환경도 함께 확인해야 합니다.
로그인과 권한은 서로 다른 문제입니다.
Supabase Auth로 로그인에 성공했다고 해서 사용자가 자신의 데이터만 볼 수 있도록 자동 설정되는 것은 아닙니다.
예를 들어 예약 목록을 조회하는 기능에서 사용자 조건이 빠지면, 로그인한 사용자가 다른 사용자의 예약까지 조회할 수 있습니다.
로그인 성공 여부보다 다른 사용자의 데이터에 접근할 수 없는지를 확인해야 합니다.
RLS(Row Level Security)는 사용자마다 접근할 수 있는 행을 제한하는 PostgreSQL 기능입니다.
Supabase의 public 스키마처럼 API에 노출된 테이블은 RLS 설정이 중요합니다.
Dashboard의 Table Editor로 만든 테이블은 RLS가 기본 활성화될 수 있지만, SQL Editor나 직접 작성한 SQL로 만든 테이블은 별도로 활성화해야 할 수 있습니다.
RLS를 켰더라도 정책을 지나치게 넓게 작성하면 데이터가 그대로 노출될 수 있습니다.
using (true)
이 조건은 적용 대상 역할과 작업에 따라 모든 행을 허용할 수 있습니다.
SELECT, INSERT, UPDATE, DELETE 정책을 구분했는가anon인지 authenticated인지 명확한가id와 데이터의 소유자 컬럼을 비교하는가권한 판단에 사용자가 직접 수정할 수 있는 user_metadata를 사용하는 것도 주의해야 합니다. 역할과 같은 중요한 권한 정보는 사용자가 임의로 바꿀 수 없는 데이터를 기준으로 판단해야 합니다.
Supabase Storage에는 Public 버킷과 Private 버킷이 있습니다.
Public 버킷의 파일은 URL을 알고 있다면 누구나 조회할 수 있습니다. 파일명을 복잡하게 만들었다고 접근 권한이 생기는 것은 아닙니다.
Private 버킷은 RLS 정책과 인증 정보를 이용해 접근을 통제할 수 있으며, 일정 시간만 유효한 Signed URL을 사용할 수도 있습니다.
회원가입이나 문의폼에서 글자 수와 이메일 형식을 검사했다고 해도 브라우저의 검증만으로는 충분하지 않습니다.
사용자는 화면을 거치지 않고 Supabase API에 직접 요청할 수 있기 때문입니다.
NOT NULL, UNIQUE, CHECK 제약조건WITH CHECK 정책예를 들어 예약 인원을 화면에서 1명 이상으로 제한했다면 데이터베이스에도 같은 제약조건을 둘 수 있습니다.
check (guest_count >= 1)
화면 검증은 사용자의 실수를 줄이고, 서버와 데이터베이스 검증은 잘못된 요청이 저장되는 것을 막습니다.
이메일 인증, 비밀번호 재설정, 소셜 로그인을 사용하면 인증 후 사용자를 돌려보낼 URL을 설정하게 됩니다.
개발 중 사용한 localhost 주소나 임시 배포 주소가 운영 설정에 남아 있으면 인증 링크가 잘못된 화면으로 연결될 수 있습니다.
Site URL이 정확한가Supabase Auth에는 인증 API에 대한 기본 Rate Limit이 있지만, 이것만으로 서비스의 모든 API와 폼이 보호되는 것은 아닙니다.
문의 등록이나 예약 생성처럼 직접 만든 기능은 별도의 요청 제한이 필요할 수 있습니다.
초기 개발에서는 Dashboard에서 테이블과 컬럼을 직접 수정하는 것이 편리합니다.
하지만 서비스가 운영되기 시작하면 누가 어떤 구조를 변경했는지 추적하기 어려워집니다. 개발 환경과 운영 환경의 구조가 달라지는 문제도 생길 수 있습니다.
Supabase는 데이터베이스 변경사항을 Migration 파일로 관리할 수 있습니다.
supabase/migrations/
Dashboard에서 작업하더라도 변경 내용을 Migration으로 남겨 Git에서 관리하면 동일한 환경을 다시 만들고 변경 이력을 검토하기 쉬워집니다.
백업은 요금제와 설정에 따라 제공 범위와 보관 기간이 다릅니다. 따라서 프로젝트의 현재 백업 정책을 직접 확인해야 합니다.
특히 주의할 점은 데이터베이스 백업에 Storage의 실제 파일이 포함되지 않는다는 것입니다.
데이터베이스에는 Storage 객체의 메타데이터가 저장되지만, 삭제된 파일 자체가 데이터베이스 복원으로 되살아나는 것은 아닙니다.
무료 프로젝트라면 필요한 데이터를 정기적으로 내보내는 방법도 검토해야 합니다.
백업이 존재하는 것과 필요한 데이터를 실제로 복구할 수 있는 것은 다릅니다.
Supabase Database Backups 공식 문서
개발 환경에서 회원가입과 데이터 저장이 정상적으로 동작해도 운영 환경에서는 트래픽, 비용, 장애 대응까지 확인해야 합니다.
Security Advisor는 흔한 설정 문제를 찾는 데 도움이 되지만, 애플리케이션 전체의 보안을 보장하는 도구는 아닙니다. 실제 사용자 권한과 서비스 흐름은 별도로 테스트해야 합니다.
아래 항목만이라도 자신의 프로젝트에서 직접 확인해보세요.
service_role key는 서버에서만 사용한다Supabase를 사용하면 백엔드 개발 시간을 크게 줄일 수 있습니다.
하지만 빠르게 구현할 수 있다는 것이 권한과 운영 설정까지 자동으로 해결된다는 뜻은 아닙니다.
처음부터 모든 것을 완벽하게 점검하기 어렵다면 우선 다음 세 가지부터 확인해보세요.
이 세 가지는 실제 프로젝트에 테스트 계정을 만들어 직접 확인할 수 있습니다.
설정 화면만 보고 안전하다고 판단하기보다, 권한이 다른 사용자의 입장에서 직접 요청해보는 과정이 필요합니다.