← 블로그
보안

AI로 만든 앱에서 가장 자주 나오는 보안 실수 5가지

작성·검토: LaunchGuard 편집팀 · 최초 발행 2026-07-23 · 최종 수정 2026-07-25 · 8분 읽기

Lovable·Bolt·Cursor·Claude Code 같은 도구는 프로토타입을 빠르게 완성해줍니다. 문제는 "작동한다"와 "출시해도 안전하다" 사이에 있는 간극입니다. AI는 기능을 만들어주지만, 배포 단계에서 키를 어디에 둘지, 누가 데이터에 접근할 수 있는지, 보안 헤더와 개인정보 처리를 어떻게 설정할지는 결국 사람이 결정해야 합니다. 아래 다섯 가지는 실제 출시 전 점검에서 반복적으로 나오는 패턴이며, 대부분은 공개 URL만으로 직접 확인할 수 있습니다.

1. 비밀 키가 브라우저 코드에 그대로 노출

결제·DB 관리자 키(예: Supabase service_role, Stripe sk_live_)가 프론트엔드 번들에 박혀 있는 경우입니다. 브라우저 개발자 도구의 Network 탭이나 번들 파일(main.js 등)을 열어 service_role, sk_live_ 같은 문자열이 보이면 즉시 위험입니다. AI 도구는 종종 "빠르게 작동하게" 만들 목적으로 강한 키를 클라이언트 코드에 넣어버리는데, 이 키 하나로 방문자 누구나 데이터베이스를 통째로 조작할 수 있습니다.

핵심 구분은 공개되어도 되는 키서버에만 있어야 하는 키입니다. Supabase는 anon 키(공개 가능, RLS 통제)와 service_role 키(RLS 우회, 서버 전용)를 분리해서 제공합니다.

// 잘못된 예: 관리자 키를 브라우저에서 직접 사용
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(URL, process.env.SUPABASE_SERVICE_ROLE)
// → service_role 은 RLS 를 무시하므로 누구나 모든 행을 읽고 지울 수 있음

// 올바른 예: 브라우저는 anon 키만, 민감 작업은 서버 라우트로
const supabase = createClient(URL, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)
// 결제·관리 작업은 /api/admin/* 라우트에서 service_role 을 서버에서만 사용

2. .env · .git 파일이 웹에서 그대로 열림

배포 설정 실수로 /.env/.git/config가 200 OK로 응답하는 경우입니다. 설정·소스가 통체로 노출되는 가장 흔한 실수 중 하나입니다. 정적 호스팅에서 빌드 결과물 폴더에 .env가 같이 업로드되거나, 서버가 점(.)으로 시작하는 파일 접근을 막지 않은 경우 발생합니다.

# 배포된 도메인에서 직접 확인 (200 + 내용이 보이면 노출)
curl -I https://내도메인/.env
curl -I https://내도메인/.git/config
# 기대 결과: 404 Not Found

3. 인증 없이 보호된 API에 접근 가능

로그아웃 상태로 /api/orders 같은 보호 엔드포인트를 호출했는데 200과 함께 데이터가 그대로 보이는 경우입니다. RLS(Row Level Security)나 미들웨어 인증 체크가 빠졌을 때 발생합니다. 로그인 화면이 있어도 서버 정책이 없으면 API를 직접 호출해 다른 사용자의 데이터를 읽을 수 있습니다.

// 로그아웃 상태(쿠키 없음)에서 보호 API 호출해보기
const res = await fetch('https://내도메인/api/orders', { credentials: 'omit' })
console.log(res.status, await res.json())
// 기대 결과: 401 Unauthorized 또는 403 Forbidden
// 실제로 200 + 주문 데이터가 오면 인증이 빠진 것

4. 쿠키·보안 헤더 미설정

세션 쿠키에 HttpOnly·Secure·SameSite 속성이 없거나, 기본 보안 헤더(CSP, X-Frame-Options, Strict-Transport-Security 등)가 비어 있는 경우입니다. 세션 탈취·클릭재킹 위험으로 이어집니다. 쿠키에 HttpOnly가 없으면 자바스크립트로 토큰을 훔치기 쉽고, Secure가 없으면 공용 Wi-Fi 등에서 가로챈 요청이 평문으로 전송됩니다.

# 보안 헤더 응답 확인
curl -sI https://내도메인 | grep -iE 'set-cookie|x-frame|content-security|strict-transport'
# Set-Cookie 에 HttpOnly; Secure; SameSite=Lax 포함 여부 확인

5. 개인정보처리방침·회원탈퇴 경로 없음

이름·이메일·전화번호 같은 개인정보를 다루면서 처리방침이나 탈퇴 기능이 빠져 있는 경우입니다. 한국에서는 개인정보를 다루는 서비스에 법적으로 필요한 항목입니다. 가입은 쉽게 만들어놓고 탈퇴나 데이터 삭제는 빠져 있는 경우가 많으며, 이는 단순한 UX 문제가 아니라 규정 위반 소지가 있습니다.

참고 — 위 다섯 가지 중 1·2·4·5번은 공개된 URL만으로 확인할 수 있습니다. 3번(인증 우회)은 실제 로그인 상태와 비교해야 확인되는 경우가 많아 테스트 접근이 있으면 더 정확합니다.

배포 플랫폼별 대응 요약

같은 실수라도 플랫폼에 따라 막는 위치가 다릅니다. 아래 표는 각 환경에서 가장 빠르게 적용할 수 있는 대응 지점입니다.

플랫폼키 노출 방지.env / .git 차단
Vercel환경변수를 Sensitive 로 표시, NEXT_PUBLIC_ 접두사는 anon 공개 키에만빌드 출력(.next)에 .env 미포함; vercel.json 헤더·리다이렉트로 dotfile 차단
NetlifySite settings → Environment 변수에 시크릿 저장, 클라이언트 노출 변수 분리_redirects / netlify.toml/.env 404 처리, 빌드 명령에서 .env 제외
Supabaseservice_role 은 서버 라우트/Edge Function 환경에만, anon 만 클라이언트Storage 버킷 정책 별도 점검, 공개 스키마 전 테이블 RLS 활성화
Cloudflare PagesSettings → Variables 에 암호화, 클라이언트용 변수만 PUBLIC_ 접두사_headers / _redirects 로 dotfile 404, 빌드 출력 디렉터리 점검

어느 플랫폼이든 공통 원칙은 하나입니다. "서버 전용 키는 서버 환경변수에만, 빌드 결과물에는 민감 파일이 들어가지 않게, 그리고 배포 후 실제로 URL을 열어 404가 뜨는지 확인할 것."

출시 전 점검 체크리스트

실수 다섯 가지를 한 번에 점검할 수 있도록 바로 쓸 수 있는 체크리스트입니다. 공개 URL만으로 확인 가능한 항목과 로그인 테스트가 필요한 항목을 구분했습니다.

공식 참고 자료

자주 하는 질문

AI로 만든 앱인데 이런 실수가 정말 흔한가요?

네. Lovable·Bolt·Cursor 같은 도구는 화면과 기능을 빠르게 완성해주지만, 서버 전용 키 분리·RLS·보안 헤더 같은 배포 단계의 보안은 개발자가 직접 채워야 합니다. 출시 전 점검에서 키 노출·.env 노출·인증 누락이 반복적으로 나타나는 이유입니다.

service_role 키가 브라우저에 노출된 것 같습니다. 당장 뭘 해야 하나요?

Supabase 대시보드에서 해당 키를 회전(rotate)해 새 키로 발급받고, 코드에서 service_role을 서버 환경변수로만 옮기세요. 키는 노출된 순간 이미 유출된 것으로 보아야 하므로, 파일에서 지우는 것만으로는 부족합니다.

개인정보처리방침은 어떤 항목을 적어야 하나요?

수집하는 항목(이메일·이름 등), 수집 목적, 보관 기간, 제3자 제공 여부, 이용자 권리(열람·정정·삭제·탈퇴)와 그 청구 경로를 포함해야 합니다. 한국 서비스라면 만 14세 미만 이용자 보호 규정과 개인정보 보호책임자 연락처도 필요합니다.

내 서비스에 이 문제들이 있는지 지금 확인해보세요

URL만 넣으면 무료로 확인해드립니다. 가입 불필요.

무료 요약 받기