SESSION 04 / 06

F12 누르면
다 보인다

F12 · 6 방어선 · 보안 감사 · account.md

지준영

비전공(경영학과) → 기자 · 해외영업 → 개발자 전향
iOS · Android · Frontend 약 5년 반 (6년차)
대기업 협업툴 iOS/macOS 앱 개발
2026~ 바이브코딩으로 웹 · 서버 1인 개발 · 사업화

PART 1 — 3화 복기

오늘은 좀
무서운 얘기를 하겠습니다.

WHY WEB IS WILD

웹·서버는 야생입니다

저도 보안 담당자 무서워합니다. 저는 보안 전문가가 아니에요.

모바일 vs 웹 — 개발자 책임 영역이 다릅니다

iOS · Android
애플·구글이 절반은 막아줌

Sandbox · Code Signing · ATS · Keychain · 앱마켓 심사 — OS·플랫폼 차원의 기본 보안

웹 · 서버
전부 개발자 책임

HTTPS · CORS · CSRF · XSS · SQL Injection · DDoS · 서버 OS · 인증·인가 — 전부 직접

웹은 AI가 가장 많이 학습한 분야

AI
평균치는 정말 잘 만듭니다

로그인·게시판·대시보드 — 학습 분포의 *평균값*. 기능 동작에 강함.

해커 · 봇
평균치 외 영역을 찌릅니다

엣지 케이스, 비정상 입력, 특수 조건. 학계 용어 — adversarial robustness

챙기면 잘 굴러갑니다. 안 챙기면 망합니다.
오늘 6가지 방어선 = 챙기는 최소한.

EDGE CASE · 결제

평균치 완전히 벗어나는 대표 — 결제 붙이기

"5분 안에 된다? 튜토리얼대로 하니까 되더라?"

해보십시오. 매출 안 나오면 모르고, 폐업하고 묻고 넘어갈 수도 있습니다.
매출이 많아지고, 표적이 되면 — 그때 알게 됩니다.

결제 = 수많은 절차와 분기가 한겹 한겹 계층으로 쌓이는 가장 복잡한 기능.
그 계층들 간의 모순이 없어야 함. AI 평균치 코드가 거의 안 다루는 엣지가 폭발.

멱등성 원자성 동시성 Webhook 검증 금액 검증

왜 무서운가 — 익숙한 두 가지

iOS 인앱결제 — 옛날 게임사들이 고통받았던 그 영역. Apple 30% 수수료 · 자동갱신 · 환불 · 영수증 검증 …
중소기업 CS — 결제 사고 시 고객 분노 직격. "내 돈 어디 갔냐" 폭언, 별점 1점 폭주, 평판 한 달 만에 붕괴.

강사 본인 고민

결제 — 제가 지금 제일 고민하는 부분

제가 강의 때 소설 올리는 서비스 몇 번 보여드렸죠?

제가 지금 제일 고민을 많이 하는 부분이 이겁니다
결제 기능의 공격 포인트 방어하기.

F12 · DEVTOOLS

F12는 브라우저의 X-ray입니다.

크롬 기준 — 아무 페이지에서 마우스 오른쪽 → 검사.
또는 클로드한테 *"내 컴퓨터가 윈도우/맥 어떤 거야? '웹개발자 도구' 어떻게 열어?"*

Network 탭에 보이는 것

API 호출 경로 · 요청 내용 · 응답 내용
어떤 AI 모델을 쓰는지 · 환경변수 · localStorage · 쿠키
전부 공개 상태입니다.

병원 X-ray로 뼈가 보이는 건 정상입니다.
내가 내 컴퓨터에서 확인하는 것도 해킹이 아닙니다.

문제는 — 누구나 열 수 있다는 것.
브라우저는 개발자 편인지 해커 편인지 구분하지 않습니다.

TWO RISKS

F12로 보이는 게 위험한 두 가지 이유

위험 ①
사용자가 털린다
이메일·결제·개인정보 노출.
보안·돈 문제와 직결.
잠시 후 사고 3건으로 증명.
위험 ②
내가 털린다
AI 모델·프롬프트·로직
핵심 레시피 전부 노출.
경쟁자가 주말 복붙으로 카피.

F12는 사용자 보호이면서 동시에
내 아이디어 보호의 문제입니다.

ANALOGY

진짜 보안 = "가져갈 수 있느냐"

방 서랍 비유

내 방에서 내 일기장 꺼내보는 건 사고 아님.
진짜 사고는 도둑이 창문 깨고 들어와 훔쳐가도록 방치하는 것.

놀이공원 팔찌 — 어디에 보관하느냐가 전부

A. 공용 테이블
localStorage
외부에 노출되면 안 되는 키값·인증값을 다 때려넣는 행위 = 도둑이 바로 집어감
B. 은행 금고
HttpOnly Cookie
X-ray로 보이지만 꺼낼 수 없음

같은 팔찌여도 어디 두느냐에 따라 달라집니다.

"도둑"의 정체 = XSS 공격자

누가 페이지에 악성 자바스크립트를 심어놓은 상황 (Cross-Site Scripting).
localStorage는 같은 도메인 JS가 다 읽음 → 악성 스크립트가 토큰 탈취.
HttpOnly 쿠키는 JS에서 아예 안 보임 → 못 훔침. HttpOnly의 본업 = XSS 발생해도 토큰 못 훔치게.

PART 2

10초 공격
실제 사고 3건

해커가 1인개발자 사이트를 터는 데
10초도 안 걸립니다.

INCIDENT 01

EnrichLead — 2일 공격 · 1주일 폐업

문제 — 기본 방어선 4가지가 전무

창업자가 "한 줄도 안 썼다"고 자랑한 B2B 리드 SaaS.
API 키 프론트 노출 · 인증 없음 · DB 무방비 · rate limiting 없음.

공격 경로

브라우저 콘솔로 결제 우회 → 유료 기능 무료 사용 → API 키 소진.
Cursor로 고치려 시도 → "다른 부분만 계속 깨뜨렸다" → 포기·폐업.

KEY TYPES · 두 종류 구분

공개 키 (Public)
앱·브라우저에 박아도 OK
Firebase apiKey · Google Maps · Stripe pk_* · Supabase anon
→ 단 *제한·정책*(Security Rules·App Check·Restrictions) 반드시 켜기.
시크릿 키 (Secret)
절대 클라이언트 X
Anthropic sk-ant-* · OpenAI sk-* · Stripe sk_* · Supabase service_role
→ 무조건 백엔드 환경변수.

자가 진단 — *"이 키 노출되면 누구나 호출해서 *돈* 나가거나 *권한* 얻나?"* YES → 시크릿. NO → 공개.

교훈 — 시크릿 키는 안전한 곳에.
웹·서버 구조면 백엔드 환경변수에 격리. iOS·Android 앱은 자체 백엔드 거쳐 호출. 공개 키는 박아도 OK 단 *정책 반드시*.

INCIDENT 02

Moltbook — API 키 150만 건 유출

사고 경위 — 이중 실수

창업자 Matt Schlicht가 "한 줄도 안 썼다"고 선언한 AI 에이전트 소셜 플랫폼.
Supabase 기반 · RLS 꺼짐 + 권한 있는 키가 클라이언트 JS에 노출.
anon 키 자체는 공개해도 OK. 단 *RLS 꺼짐* + *시크릿 키 노출* 조합이 사고 원인.

결과 — API 키 150만 건 · 이메일 3.5만 건 · 에이전트 개인 대화 전체 유출.
보안회사 Wiz Research가 조사 공개.

교훈 — Supabase RLS · Firebase Security Rules 무조건 켠다.
Claude한테 매번 체크시키기.

INCIDENT 03

Tea 앱 — 이미지 7.2만 + 메시지 110만

1차 유출 (2025년 7월)

여성 전용 앱. 가입 시 운전면허·셀피 수집.
Firebase Storage 권한을 누구나 접근 가능한 상태로 방치.
이미지 7.2만 건 유출 — 운전면허 포함 셀피 약 1.3만 건.

2차 유출 (며칠 뒤)

개인 메시지 110만 건까지 추가 유출.
낙태 상담, 불륜 고민 등 극히 민감한 대화 포함.

교훈 — 파일 업로드 기능 있으면
Storage 권한 반드시 체크.

KBS 창 540회 · 봐야 할 두 구간

방송은 완성된 결과만 보여줍니다

"나의 완벽한 비서 · AI 에이전트 시대" · youtu.be/QQJpyIO014A

사건 ① · 영상 도입부 (초반) — 다큐 주인공

보안업계 스타트업 CEO · 발리 거주 · 하루 30분 근무 · 에이전트 결과만 승인

그 사람이 거기까지 가는 데 우리가 짐작만 할 수 있는 4가지 —

Q1
얼마나 많은 연구개발?
Q2
얼마나 많이 배운 사람?
Q3
얼마나 많은 시행착오?
Q4
한 달 토큰 몇천만원?

(참고 — 팔란티어 엔터프라이즈 월 2천만원+ 내는 회사도 있어요.)

사건 ② · 28~32분 구간

호텔 예약 자동화 에이전트에게 *"50만원만 쓰라"* 지침이 76만원 결과.

KAIST 연구진 + KBS 스태프가 만든 통제된 공격 실험. 외부 웹페이지에 심어둔 공격적 코드·프롬프트가 에이전트를 오동작시키는 시나리오. 실제 피해자 아님.

강사 출신 — 잡지사 기자 (1화 첫날 소개). 미디어 작동 방식은 편집부 의도의 결과.

집에서 영상 보면서 두 가지 확인
① 사건 ① CEO의 노력·공부·시행착오·비용 — 화면에 나오나?
② 사건 ② 공격 메커니즘(어텐션·툴 콜링·판단·IDPI) — 명확하게 나오나?

안 나왔다면 — 편집에 잘려나간 것. 그게 미디어의 본질.

결정적 질문 —
"내가 만드는 서비스는, 그 공격을 방어할 준비가 되어 있는가?"

↓ 4화 본론(6가지 방어선)으로 가는 다리

PART 3

기본 방어선
6가지

외울 필요 없습니다. 사진 찍어가세요.
Claude한테 "이것도 같이" 한 줄이 핵심.

TODAY · 6 BASIC DEFENSES

기본 방어선 6가지 — 한눈에

① 데이터베이스
RLS (Row Level Security) 켜기

데이터베이스의 한 줄(행)마다 *누구 소유*인지 표시 → 본인 행만 읽기·쓰기.
예: "내 글은 나만, 남의 글은 못 보게"
Supabase·Firebase 디폴트 OFF — 안 켜면 누구나 모든 행 접근.

② 키 관리
API 키 코드에 박지 마라

하드코딩한 키는 GitHub에 올라가는 순간 전 세계 노출. .env로 분리.

③ 환경변수 노출
NEXT_PUBLIC_ 주의

NEXT_PUBLIC_·VITE_·REACT_APP_ 접두사 붙은 키는 번들에 박혀서 브라우저 노출.

④ AI 호출 위치
AI 호출은 서버에서

OpenAI·Anthropic 키를 클라이언트(브라우저·앱)에 박아두고 호출하면 즉시 탈취. BFF/API Proxy 패턴.

⑤ 빌드 산출물
Source Map 끄기

Production에 .map 노출되면 난독화 코드 → 원본 복원. productionBrowserSourceMaps: false

⑥ Git 위생
.gitignore.env

실수로 .env 커밋되면 — push 후 30분 내 봇이 키 자동 수집.

이 여섯, 하나씩 풀어 갑니다.

IF YOU SKIP — WORST CASE

6개 다 안 하면 — 무슨 일이 생기나

💰 돈
"몇천 깨지는 건 일도 아닙니다"

API 키 노출 → 자동 봇이 30분 내 수집 → OpenAI·AWS 청구서 폭주.
한 달 만에 수천만 원 ~ 수억 가능.

📋 법적 책임
"고객정보 털리면 — 고소"

개인정보보호법 위반 → 매출의 최대 3% 과징금 + 피해자 1인당 손해배상.
집단소송 시 영세 사업자도 사장 개인 파산 가능.

🔒 인질
"DB 뚫리면 — 데이터 인질"

랜섬웨어로 DB 암호화 → 비트코인 몸값 요구.
백업 없으면 사업 자체 종료. 평균 몸값 글로벌 80만~150만 달러.

📉 평판
"평판 붕괴 → 매출 0"

별점 1점 폭주·X(트위터) 박제 → 한 달 안에 신뢰 회복 불가.
"그 사이트 결제 사고 났대" 한 줄이 곧 매출 0.

이 네 개 — 6방어선 중 한 개만 빠뜨려도 발생합니다.
패가망신. 과장 X. 실제 사례 매주 나옵니다.

DEFENSE 01
Supabase RLS · Firebase Security Rules를 켜라
대시보드 경고 ⚠️가 뜨면 즉시 켭니다.
# Claude에게 한 줄 덧붙이기 "테이블 만들어줘, RLS 정책도 같이 만들어줘"

이 한 줄로 Moltbook 사고는 예방됩니다.

RLS — 쉽게

RLS가 뭔가요? — 아파트 우편함

비유

아파트 1층 우편함, 100세대 우편함이 다 있어요.
"내 집 우편함은 나만 열 수 있다" — 이게 정상.
→ RLS 켠 상태 = 정상

안 켜면?

입주민 누구나 100세대 우편함 다 열 수 있다.
이웃집 통장, 카드 청구서, 등기우편 다 열람 가능.
→ Supabase·Firebase 디폴트 OFF. 안 켜면 누구나 모든 사용자 데이터 읽기·수정 가능.

RLS = "이 데이터 한 줄(행) 소유자만 열 수 있다"
한 줄로: 우편함마다 자물쇠 달아두는 것.

DEFENSE 02
API 키를 코드에 박지 마라
.env 파일 + 호스팅 대시보드 환경변수 기본.
# .env (Git에 올리지 않음) OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... # 코드에서는 변수로 process.env.OPENAI_API_KEY

Vercel · Netlify는 대시보드 '환경변수' 입력칸에 넣으면 됩니다.

API 키 — 쉽게

시크릿 API 키가 뭔가요? — 호텔 마스터 키

비유 (시크릿 키 한정)

호텔 직원이 가진 마스터 키 — 모든 객실 다 열림.
OpenAI·Anthropic·AWS *시크릿 키*도 똑같아요. "이 키만 있으면 그 회사 서비스 마음대로 쓸 수 있음."
→ 사용량은 키 주인(나)에게 청구. *공개 키*는 다른 종류 — S10 분류 참조.

코드에 박으면?

호텔 마스터 키를 호텔 정문에 자물쇠 안 채우고 걸어둔 상태.
지나가는 누구나 떼서 객실 다 열고 미니바·금고 털어감.
→ GitHub에 키 올라가면 30분 내 봇이 수집 → OpenAI 청구서 폭주, 한 달 만에 수천만 원~수억.

코드에 박지 말고 — .env 라는 별도 파일에 분리.
.env는 절대 Git에 올리지 말 것 (다음 슬라이드에서).

DEFENSE 03
NEXT_PUBLIC_ 접두사에 주의하라
이 접두사 = "세상에 공개"입니다.
❌ 위험
NEXT_PUBLIC_OPENAI_KEY
브라우저에 그대로 노출
✓ 안전
OPENAI_KEY
서버에만 존재

EnrichLead 사고가 정확히 이 실수였습니다.

다른 프레임워크도 같은 룰 — VITE_ (Vite) · REACT_APP_ (CRA). 이름은 달라도 *'클라이언트에 노출'* 은 동일.

단, *공개 키*에는 붙여도 OK

Firebase apiKey, Stripe pk_*, Supabase anon 같은 *공개 키*는 NEXT_PUBLIC_*·VITE_* 붙여도 OK. 어차피 공개 의도된 키니까요.
→ 시크릿 키만 절대 X. S10 분류 참조.

NEXT_PUBLIC_ — 쉽게

NEXT_PUBLIC_이 뭔가요? — 가게 간판 vs 사장 금고

비유

가게에 두 종류 글자가 있죠.
간판 = 행인 누구나 봄 (전화번호·주소·메뉴).
사장 금고 안 = 직원도 못 봄 (현금·도장·통장).
NEXT_PUBLIC_ 접두사가 붙은 키 = 간판에 적힌 글자. 빌드 시 브라우저로 그대로 새어나감.

실수로 *시크릿 키*에 붙이면?

사장 금고 비밀번호를 간판에 써두는 격.
OpenAI sk-*·Supabase service_role 같은 시크릿 키NEXT_PUBLIC_ 붙이면 → F12 한 번에 도둑 손에.
VITE_·REACT_APP_도 같은 원리. 다른 프레임워크의 같은 함정.

규칙: 접두사 = '클라이언트로 새어나감'이라는 표시.
→ 이 자리에는 *공개 키*만 (Firebase apiKey, Supabase anon, Stripe pk_*). *시크릿 키*는 절대 X — 사장 금고 비번을 간판에 박는 순간.

DEFENSE 04
AI 호출은 서버에서
BFF 프록시 패턴 — 내 서버가 중계합니다.
브라우저 → 내 서버 (API Route) → OpenAI API ↑ 여기서만 API 키 사용

Claude에게: "서버 사이드 API Route에서 호출해줘" 꼭 붙이기

PLATFORM · 플랫폼별 적용

Next.js · Vite · Nuxt
서버 사이드 API Route (Next.js /api/*, Vite는 별도 Express·Hono·Vercel Functions)에서만 호출. 키는 백엔드 환경변수.
iOS
Swift · SwiftUI
앱 안에 키 박지 X (IPA 디컴파일로 추출됨). 자체 백엔드 거쳐 호출. 사용자 토큰만 Keychain 저장.
Android
Kotlin · Jetpack
앱 안에 키 박지 X (APK 디컴파일로 추출됨). 자체 백엔드 거쳐 호출. 사용자 토큰만 Keystore 저장.

→ 공통 원리 — *시크릿 키*(OpenAI·Anthropic·Stripe `sk_*`·Supabase service_role 등)는 *반드시* 자체 백엔드에서만 사용. 사용자 인증 토큰(JWT·OAuth)은 OS Keychain/Keystore에. 셋은 다른 종류.

자주 나오는 혼동 — "Firebase는 Info.plist에 키 그냥 넣으라던데?"

맞아요. Firebase apiKey*공개 키* — *그 자체로 권한 없음*. 그래서 앱에 박아도 OK.
단 진짜 방어선은 Firebase Security Rules + App Check. Google Maps key·Stripe `pk_*`·Supabase `anon`도 같은 결.

→ S10 *공개 키 vs 시크릿 키* 표 다시 떠올리기. 시크릿만 백엔드, 공개는 앱 OK 단 *정책 켜기 필수*.

BFF — 쉽게

BFF가 뭔가요? — 손님 / 직원 / 사장

비유 — 식당

손님 = 사용자 (브라우저)
직원 = 내 서버 (BFF · Backend For Frontend)
사장 = 외부 API (OpenAI·은행·결제)
→ 손님이 사장 사무실 직접 들어가서 금고 만지면 X. 직원이 손님 부탁 받아 사장에게 전달.

손님이 사장 직접 만나면?

손님이 사장 금고 비번(API 키) 다 알게 됨.
그 다음 손님은 다른 손님인 척하고 매일 식당 와서 금고 털어감.
→ 클라이언트에서 OpenAI·은행 직접 호출 = API 키 노출. 봇이 수집해서 청구서 폭주.

규칙: 손님은 직원만 만난다. 직원이 사장에게 전달.
즉 — AI·결제·DB 호출은 반드시 내 서버(BFF)에서. 클라이언트 X.

DEFENSE 05
Production Source Map을 끄라
켜져 있으면 원본 코드가 F12에 그대로 보입니다. 주석까지.

Source Map이 뭐길래?

여러분 코드(TS·JSX·최신 JS) → 빌드 도구가 압축·번역·하나로 묶기 4단계 변환 → 브라우저로 보냄. 변환 후 코드는 사람이 못 읽음.

버그 디버깅 위해 — *원본 ↔ 압축본 번역 대조표* 를 빌드가 따로 만듭니다. 그게 .map 파일 = Source Map.

비유 — 한국어 책 영역(英譯)본의 *번역 대조표*. 영역본에 오타 나면 한국어 어디였는지 찾을 때 쓰는 사전.

같은 함수 — 원본 vs 빌드 후 (사람이 짠 거 vs 브라우저로 가는 거)

// 원본 function calculatePriceWithVAT( basePrice, additionalFee) { // VAT 10% 적용 return basePrice*1.1+additionalFee }
// 빌드 후 (압축) function n(a,b){return a*1.1+b} // 한 줄, 변수 한 글자. // 주석 다 사라짐.

Source Map 켠 채로 운영 올리면 → F12에서 왼쪽(원본) 그대로 보임. 함수가 뭘 하는지 · 비즈니스 로직 · 주석 메모 다 노출.

DEFENSE 05 · 설정 + 의도 분류

Source Map — 한 줄 설정 + 다른 회사는 왜?

// next.config.js — 한 줄 module.exports = { productionBrowserSourceMaps: false } // Vite는 build.sourcemap: false

"근데 왜 다른 회사는 켜놨던데요?" — 의도 5가지 분류

모르고 켜놓음 — 빌드 기본값, F12 점검 안 함

70~80%

"프론트는 어차피 공개" 철학 — 시간 차이(5초 vs 며칠) 무시

15~20%

디버깅 편의 — Sentry·Datadog 안 쓰는 작은 팀

5~10%

오픈소스·마케팅 — Vue·React, Stripe·Linear

5%

"moat는 코드가 아니다" — Netflix·Spotify 류 대기업

극소수

→ 1인 창업자·소상공인에게 ⑤ 적용 X. 여러분의 moat = 핵심 로직·프롬프트. 80%(몰랐음) 카테고리에 있을 가능성이 큼 — 한 번 확인하고 끄세요.

Claude에게: "이 프로젝트 production build에서 source map 노출되는지 확인해줘"

ADVANCED · 고급 옵션

hidden-source-map보안 + 디버깅 둘 다 잡는 표준 패턴

옵션 둘 중 선택

완전 끄기 (`sourcemap: false`) — 가장 안전. 단 운영 에러 추적 어려움.
hidden-source-map — *생성*은 하되 sourceMappingURL 주석을 안 박음. 일반 사용자 F12에는 안 보임.

hidden-source-map 동작 방식

생성된 .map 파일을 서버 배포에 포함하지 않고 — Sentry·Datadog 같은 에러 추적 서비스에 *별도 업로드*.
→ 운영 중 에러가 나면 Sentry 대시보드에서 *원본 라인까지* 추적 가능. F12로는 못 봄.

프레임워크별 옵션

Next.js — productionBrowserSourceMaps: false + Sentry 연동
Vite — build.sourcemap: 'hidden'
Webpack — devtool: 'hidden-source-map'
CRA — GENERATE_SOURCEMAP=false (CRA는 hidden 미지원)

한 줄 — 완전 끄기는 가장 안전, hidden은 *보안 + 디버깅* 둘 다 챙김.
규모가 커져서 Sentry·Datadog 쓸 때 자연스럽게 hidden으로 전환.

Source Map — 쉽게

Source Map이 뭔가요? — 건물 설계도

비유

건물 다 짓고 외관만 보면 — 일반인은 환기구·비밀통로·금고 위치 못 찾음.
설계도가 있어야 어디에 뭐가 있는지 다 보임.
→ Source Map = 압축된 코드 ↔ 원본 코드 *번역 대조표*. 이게 있으면 F12에서 원본 그대로 보임.

설계도 외부에 공개하면?

도둑이 건물 전체 환기구·비밀통로·금고 위치 다 알게 됨.
건물 외관은 그대로인데 들어오는 길이 무한히 많아짐.
→ Production에 .map 노출되면 비즈니스 로직·보안 검증 코드·주석 메모 다 보임. 약점 즉시 발견.

규칙: 건물 다 지었으면 설계도는 회사 금고에. 외부 공개 X.
productionBrowserSourceMaps: false 한 줄.

DEFENSE 06
.gitignore에 .env를 넣어라
Git에 올라가는 순간 1분 안에 해커 봇이 감지합니다.
# .gitignore .env .env.local .env.*.local

실수로 커밋한 상태면 — Git 히스토리에 남습니다.
키를 즉시 재발급하세요.

Git · .gitignore · .env — 쉽게

Git이 뭔가요? — 일기장 백업

비유

Git = 일기장 자동 백업 시스템 (매일 클라우드에 사진 찍어 저장)
.env = 비밀일기 (비밀번호·통장 비번·일기 속 누구 험담)
.gitignore = "이건 백업하지 마" 명단
→ Git은 모든 파일을 자동으로 클라우드에 올림. 비밀일기는 .gitignore에 적어둬야 안 올라감.

.gitignore에 안 적으면?

비밀일기까지 클라우드에 자동 백업됨. 그것도 *영원히* 히스토리에 박힘. 한 번 올라간 비번은 — 키 즉시 재발급해야.
→ GitHub에 .env 실수로 커밋되면 30분 내 봇이 키 자동 수집. AWS·OpenAI 청구서 폭주. 사후 삭제해도 히스토리에 남음.

규칙: .gitignore.env·.env.local·.env.*.local 무조건 추가.
새 프로젝트 만들 때 가장 먼저 할 일.

6 DEFENSES — CHECKLIST

01
RLS 켜기
02
API 키 코드에 박지 마라
03
NEXT_PUBLIC_ 주의
04
AI 호출은 서버에서
05
Source Map 끄기
06
.gitignore에 .env

이 여섯 개만 체크해도
오늘 본 사고 세 건 전부 예방됩니다.

KEY MANAGEMENT · 통합 정리

내 서비스를 굴리는 수많은 키들 — 어떻게 구분하고 관리하지?

한 서비스 — Supabase anon · Firebase apiKey · OpenAI sk- · Stripe pk_·sk_ · Google Maps · Anthropic sk-ant- ... 키만 5~10개 흔함.

① 비교적 공개된 공간에 적어도 OK
공개 키 (Public)

Firebase apiKey · Google Maps · Stripe pk_* · Supabase anon
→ *식별용*. 그 자체로 권한·돈 없음.

② 절대로 공개되면 안 되는 키
시크릿 키 (Secret)

Anthropic sk-ant-* · OpenAI sk-* · Stripe sk_* · Supabase service_role
→ 백엔드 환경변수만.

간단 자가 진단 — "이게 털리면 — 내가 *요금*을 내는가? / 내 *데이터베이스*가 뚫리는가?"

YES → 시크릿. 백엔드만.  |  NO → 공개. 클라이언트 OK 단 *추가 방어법 필수*.

공개 키를 안전하게 — 추가 방어법

① 정책 (RLS / Security Rules)

DB 행/문서 단위로 *"이 사용자는 자기 것만"*. Supabase RLS · Firebase Security Rules.

② 도메인·번들 제한

Application Restrictions — Google Maps key는 *내 도메인·번들 ID에서만 호출 가능*. 다른 곳에서 쓰면 거절.

③ App Check / 출처 검증

Firebase App Check — 진짜 내 앱에서 온 호출인지 검증. 봇·스크래핑 차단.

+ 시크릿 키는 무조건 — .env 분리 · .gitignore에 등록 · 백엔드 환경변수에만.

한 줄 — 공개 키 + 정책 = 안전. 공개 키만 + 정책 X = 그냥 폭망.
키만 박는 게 보안의 끝이 아니라, *정책까지 켜는 것*이 보안의 절반.

10분 휴식

잠시 후 돌아와서
"클로드는 까먹는다" 얘기를 하겠습니다.

PART 4

클로드는 까먹는다
+ AI로 AI 감시

TODAY · 10원칙 추가 2개

후반부에 — 10원칙 중 2개를 더 추가합니다.

07
기본기는 갈굼의 무기다
08
직접 깎아봐야 한계가 보인다

이 둘, 후반부에서 풀어 갑니다.

먼저 — 클로드의 *"기록해놨습니다"* 거짓말 + account.md 해결책부터.

PART 4 — CLAUDE FORGETS

"기록해놨습니다" — 믿지 마라.

강사 실제 경험

Claude에게 — "이거 좀 기록해놔라" 라고 명령.
"네, 기록해놨습니다" 라고 답함.
다음 세션에 물어봤더니 — 모름. 사실 기록 안 한 일이 비일비재.

Claude는 매 세션마다 처음부터 시작합니다.
기억이 없어요. 3화에서 얘기했죠.

더 심한 경우

심하면 — 같은 세션 안에서도 2시간 전에 얘기한 걸 기억 못 합니다.
→ 컨텍스트가 길어질수록 앞쪽을 흐릿하게 처리. 3화에서 박은 *Context Rot* 그대로.

Claude가 "기록했다"고 하면 — 반드시 확인.
중요한 건 여러분이 직접 적어둡니다.

해결책 — 사람이 직접 메모

account.md (.gitignore에 추가)

키 발급 출처 · 클라우드 계정 이메일 · 인프라 설정값 · 컨테이너 이름
암호는 절대 넣지 말 것

# CLAUDE.md에 추가할 보안 섹션 ## 보안 규칙 - .env는 절대 Git에 커밋하지 않는다 - API 키는 서버 사이드에서만 사용한다 - Supabase 테이블은 RLS를 켠 상태로 유지한다 - 이 규칙을 어기면 즉시 알려달라

규칙이 늘어나면 — 별도 파일로 분리

보안 규칙이 길어지면 SECURITY.md로 빼고 CLAUDE.md에서 *참조*만 거는 것도 좋습니다.
→ 3화 *정본·참조* 패턴 — CLAUDE.md는 짧게 유지, 세부는 파일별 분리.

3화 정본 개념의 보안 실전 적용. Claude가 매 세션 이 규칙을 읽고 인식.

PART 5

AI에게
보안 감사 시키기

2화 원칙 — 문서화 · 감시 · 갈굼.
보안은 그중에도 감시가 핵심.

AUDIT PROMPT

보안 감사 프롬프트 — 이거 그대로 복붙

이 프로젝트 전체를 보안 관점에서 감사해줘. 다음 항목을 체크해: 1. Supabase 테이블 중 RLS가 꺼진 게 있는지 / Firebase Security Rules가 비어있는지 2. .env가 Git에 커밋됐는지 3. 클라이언트 코드에 *시크릿 키*(sk-/sk_/service_role)가 하드코딩됐는지 4. NEXT_PUBLIC_ 접두사가 민감한 값에 붙어 있는지 5. 유료 AI API가 서버가 아닌 클라이언트에서 호출되는지 6. production build에서 source map이 노출되는지

Claude의 감사 결과를 Gemini · Codex에 다시 던져라.
같은 AI가 자기 코드 감사하면 "문제 없는데요" 나옴. Gemini가 결과 보고서에 훈수 두고 다음 단계 잘 제시해주는 경우도 많음.
요지 — 교차 검증이 핵심.

이게 끝이 아닙니다

웹·백엔드가 방어해야 하는 항목은 무지하게 많습니다.
이 6개는 *시작점*. OWASP Top 10 · 인증 토큰 위치 · CSP · CORS · Rate Limit · SQL Injection · CSRF · SSRF · Race Condition — 끝없이 갑니다.
→ 오늘 박는 6개는 *바이브코더가 가장 자주 빼먹는* 6개.

REAL · 강의 직전 외부 점검

한 단계 더 — 외부 시점에서 돌려본 결과입니다

S36은 자기 코드 정적 분석용. 이건 결이 다름 — 사이트 한 페이지만 보고 외부 런타임 점검 (인증 토큰 위치·응답 헤더·노출 경로)

대상: 한 한국 AI 글쓰기 SaaS · 도구: Claude Chrome MCP · 명령: "보안 감사 해봐" 한 마디 · 익명 처리

① 인증 토큰 — localStorage에 박혀 있음

*_token, JWT 형식, 길이 120자.
→ 4화 핵심 안티패턴. F12 한 번이면 누구든 토큰 확인.

② 토큰 디코드 — 24시간 long-lived

HS256 · payload sub·exp 2개뿐 (iat·jti·iss·aud 누락) · 만료 +24시간.
→ 표준 access는 15분~1시간. 24시간 + jti 없음 = 탈취 시 강제 무효화 불가, 24시간 무제한 사용.

③ 보안 응답 헤더 — 5개 누락

CSP · X-Frame-Options · X-Content-Type-Options · Referrer-Policy · Permissions-Policy = 모두 없음.
→ HSTS만 켜져 있음. CSP 한 줄 있었으면 XSS 인라인 스크립트 차단됐을 텐데 — 방어선 0겹.

④ 서드파티 다수 + CSP 부재 = 공급망 공격 면적 확대

GTM · GA · 외부 CDN 다수 로드. CSP 없음 → 그 도메인 침해 시 사이트 사용자 전체에게 악성 코드 전파 가능.

결제 받는 정식 서비스 · 4화 안티패턴을 거의 다 갖춘 상태로 운영 중.
— 아직 안 털렸을 뿐, *털리기 매우 쉬운* 상태.

PRECISELY · 정확하게 설명하자면

localStorage 토큰만 박은 것 — 토론 가능 영역

시니어 웹개발자 중 *반*은 욕하고, *반*은 *"CSP·XSS 방어 잘 했으면 OK"* 라고 답함.

조합(localStorage + CSP 없음 + 24h + jti 없음)명백한 위반

토론 영역이 아니라 표준 위반. 어떤 시니어한테 보여줘도 "이건 안 돼요" 답함.

③ 한 줄로

localStorage엔 위험한 값(인증·결제·개인식별정보)은 절대 X.
다크모드·언어·UI 상태는 OK. 기밀은 X.

④ 이 서비스는

후자(② 조합)에 가까움.
localStorage 한 가지만 봐서 욕하는 게 아니라 — 조합 때문에 위험.

SO — 최소한이라도

이래서 — 보안을 최소한이라도 챙겨야 합니다

하나 — 못해서가 아니라 안 한 것

Vite + React + Vercel로 깔끔하게 만든 분들. 똑똑한 분들 맞음.
인증 토큰을 HttpOnly 쿠키로 박는 5분짜리 작업 하나를 안 한 것.

둘 — 1조원 회사도 안 합니다

EnrichLead · Moltbook · Tea — 다 결제 받던 회사들.
최소한이라도 챙기지 않았고 — 사고 한 번에 1주일 만에 폐업 (EnrichLead).

셋 — 여러분도 같은 위협 안에

바이브코딩으로 결제 붙이고 사용자 받는 그 순간 — F12 한 번이면 다 보입니다.

최소한 = 6 방어선 + account.md + 보안 감사 프롬프트.
이 셋은 무조건. 재기 불능 사고는 한 번이면 끝입니다.

마지막 한 마디

제가 던진 명령은 "보안 감사 해봐" 한국어 한 마디였습니다.
클로드가 그 한 마디로 이 정도까지 잡아왔어요.

그러면 — 공격에 *도가 튼 사람들*이 같은 사이트를 노리면 어떨까요?

TEST

테스트 — 기계가 기계를 감시한다

유닛테스트 · E2E 테스트 · UI 테스트 — 지금 외울 필요 없음.
쉽게 말하면, 자동 검증 프로그램입니다.

전통적 개발: 개발자가 직접 짬.
바이브코딩: Claude한테 시키면 됩니다.

한 줄: "이 기능에 대한 테스트 파일도 같이 만들어줘"

MARTIN FOWLER · 1999

"어떤 바보라도
컴퓨터가 이해할 수 있는 코드는 작성할 수 있다.
훌륭한 프로그래머는
사람이 이해할 수 있는 코드를 작성한다."

— Any fool can write code that a computer can understand.
Good programmers write code that humans can understand.
『Refactoring: Improving the Design of Existing Code』 (1999)

27년 전 말입니다.

1화 콜백 — "책이다 / 전문가 폄하 금지 / 앤스로픽도 책 학습"
이 아저씨가 그 예시. 소프트웨어 업계의 신입니다.

물론 다익스트라 알고리즘의 다익스트라, 리스코프 치환 원칙의 리스코프도 있죠.
정확히는 — 이론의 신이 아니라 엔터프라이즈 실무의 신.
분야는 다르지만, 천 년 전부터 코딩 배워도 따라갈 수 없는 신 맞습니다.

2023~2025 — 지금도 현역

martinfowler.com · Exploring Generative AI 시리즈 운영 중.
27년 전 책의 저자가, AI 시대 코딩에 대해서도 계속 글을 씁니다.

즉 — 여러분의 클로드도, 이 양반 글을 다 학습했을 겁니다.

바이브코딩 시대로 한 번 비틀면 —

"어떤 AI라도 컴퓨터가 이해할 수 있는 코드는 작성합니다.
좋은 사용자는 — AI와 사람 둘 다 이해할 수 있는 코드와 문서를 작성한다."

그 시작이 — 기본기이고,
개발자들이 고민하는 아키텍처 · 디자인 패턴 · 코드 복잡도 같은 기술 용어이다.

PRINCIPLE 07
기본기는 버리는 지식이 아니라 갈굼의 무기다
직접 코드 짜려는 게 아닙니다. AI를 갈구기 위해 아는 겁니다.

F12 · RLS · NEXT_PUBLIC_ · source map · BFF 프록시 · 권한 체크 —
이 단어들을 모르면 AI가 내놓은 코드를 갈굴 수가 없습니다.

Claude가 "안전합니다" 할 때 던질 질문:
"RLS는 켰어? 이 키 클라이언트로 노출 안 돼?"

5화에서 만날 단어들도 — 다 무기가 됩니다:
클린 아키텍처 · MVVM · FSD · 멱등성 · 원자성 · 디자인 패턴 …

PRINCIPLE 08
직접 깎아봐야 한계가 보인다
배포하고 F12 눌러본 사람만 보안 감각이 생깁니다.

2회차 · 3회차 숙제를 하신 분 —
오늘 F12 눌러보면 "아 이게 이렇게 다 보이네" 실감 옵니다.

한 번도 배포 안 해본 사람은 머리로만 압니다.
눈으로 본 사람만 감각이 생깁니다.

PRINCIPLE 08 · 실전

감 키우는 가장 빠른 길 — 그림 깎아보기

코드보다 단순. 누구나 가능.

이미지 생성 AI에 — 일러스트, 풍경화, 유화, 수채화 다 시도.

강사 사례 — 제미나이 앱 첫 출시부터 100장+ 깎음. 가입한 바이크 모임방 엠블렘 직접 제작.

AI 비교 — 직접 깎아본 사람만 안다

이미지
나노바나나(제미나이) ↔ 덕테이프(OpenAI)

"덕테이프가 나노바나나를 꺾을지도" — 직접 비교.

코드
코덱스 ↔ 클로드 (개발자도 저울질)

"코덱스로 탈주? 코덱스는 리뷰만? 일은 클로드?"

강사가 직접 써본 두 모델 비유

제미나이
철학과 + 미술대 수석 졸업한 보헤미안

브레인스토밍 강함. 장문 글에서 선 넘는 비약 드러남.

클로드
법대 수석 졸업한 변호사

구체화·기승전결·논리 정합성 강함. 똑똑하지만 뺀질이 — 끊임없이 갈궈야.

AI 갈구기 방법론 — 개발자들이 활발히 연구 중

하네스 엔지니어링 — *큰 우산.* AI 작업 환경 자체를 어떻게 설계할지
에이전트 — *그 환경 안의 자율 실행 단위.* AI가 도구를 자율적으로 선택·계획·실행 (Claude Code, Cursor Composer)

같은 연구 흐름 안에 있음. 6화에서 다시.

10 PRINCIPLES — 10/10 완성

01
과장 광고를 경계하라
02
기계는 게으르고, 거짓말도 한다
03
문서화 · 감시 · 갈굼
04
직접 공부하려 하지 마라
05
기계로 기계를 감시하라
06
공부가 아니라 위임이다
07
기본기는 갈굼의 무기다
08
직접 깎아봐야 한계가 보인다
09
검증이 작업보다 오래 걸리면 실패
10
당신은 광고주, 기계는 대행사다

10원칙 전부 다뤘습니다.
이 10개가 6회 과정의 뼈대입니다.

PART 6 — HOMEWORK

오늘의 숙제

TASK 1
내 사이트에 F12 눌러보기
Network · Sources · Application 탭. 뭐가 공개돼 있는지 눈으로 확인.
TASK 2
Claude에게 보안 감사 시키기
S22의 6개 항목 프롬프트 그대로 복붙.
TASK 3
account.md + CLAUDE.md 보안 섹션
오늘 본 방어선 6가지를 CLAUDE.md에 그대로 추가.

SESSION 04 / 06

오늘도
수고하셨습니다.

다음 시간 — 5회차.
"알아서 해줘"는 통하지 않는다 — 기술 어휘의 힘.

오픈채팅 QR

질문은 카카오톡 오픈채팅으로.