t t-box 워크숍바이브 코딩 · 4시간
0% 진행
사내 개발 워크숍 · 2026-09-07(월)

t-box를 부숴보고, 제대로 다시 만든다

보안을 고려하지 않고 만든 사내 파일 공유 앱 t-box를 직접 공격해 “왜 위험한지”를 몸으로 느끼고 → AI와 함께 제대로 된 서비스를 설계한 뒤 → 그걸 완성해 오는 흐름. 코드 암기가 목적이 아니라, AI와 요구사항을 정리하고 결과를 검증하는 일하는 방식을 익히는 시간임.

4시간 개발 입문자 대상 노트북 + VM 보안 실습 포함

HOW 이 화면 사용법

  • 충님의 설명 들으며 위에서 아래로 순서대로 따라감.
  • 각 단계 “지금 할 일” 체크하면 진행률 올라감.
  • 프롬프트 카드복사 버튼으로 그대로 AI에 붙여넣음.
  • 왼쪽 목차로 언제든 이동 · 현재 위치 표시됨.

GOAL 오늘 잡을 감각

  • 보안을 고려하지 않은 서비스가 얼마나 쉽게 뚫리는지 직접 겪는다.
  • 화면에서 숨기는 건 보안이 아니다 — 서버가 막아야 한다.
  • 보안은 나중이 아니라 설계할 때부터 넣는다.
  • AI에게 만들게 하고, 의심하게 하고, 검증한다.
개념 실습 Git 커밋 해킹 타임 보안·성능

실습 안전 수칙. 오늘의 모든 공격 실습은 본인 VM의 교육용 t-box 앱 안에서만 진행함. 외부 사이트, 회사 실제 시스템, 다른 참가자 VM 대상 금지. 허가되지 않은 스캔·자동화 공격 금지.
그리고 토큰·API 키·비밀번호는 AI 대화창에 절대 입력하지 마.

0:00 – 0:15 개념 00

오프닝 · 오늘의 목표

오늘은 순서가 거꾸로임. 먼저 보안을 고려하지 않은 서비스를 직접 부숴보고, 그다음 “제대로 만들려면?”을 AI와 설계함.

충님의 설명

오늘은 개발 문법을 외우는 시간이 아닙니다. 우리가 다룰 건 t-box라는 작은 파일 공유 서비스인데, 오늘은 먼저 보안을 고려하지 않고 만든 버전을 직접 공격해볼 겁니다. 클릭 몇 번으로 남의 파일이 지워지고, 숨긴 자료가 보이는 걸 눈으로 확인할 거예요.

그렇게 “왜 위험한지”를 몸으로 느낀 다음, AI와 함께 제대로 된 서비스를 설계합니다. 그걸 직접 완성해 오는 게 오늘의 숙제예요.

AI가 코드를 대신 써줄 수는 있지만, 무엇이 안전하고 쓸 만한 서비스인지는 사람이 판단해야 합니다.

오늘의 흐름
  1. 부순다 — 보안을 고려하지 않은 t-box를 내려받아 실행하고, 직접 공격해본다
  2. 이해한다 — 왜 이렇게 쉽게 뚫렸는지, 제대로면 뭐가 달라야 하는지
  3. 설계한다 — 보안을 처음부터 넣은 PRD·아키텍처를 AI와 만든다
  4. 만들어 온다 — 제대로 된 t-box를 완성하는 게 숙제
0:15 – 0:25 개념 01

브라우저에서 앱까지 · 전체 구조

도메인을 입력하면 요청이 어떤 길을 거쳐 우리 앱에 도달하는지 파악함.

요청이 흐르는 길
  1. 브라우저사용자가 주소를 입력하고 화면을 보는 곳
  2. 도메인 · DNS도메인을 실제 서버 IP로 바꿔줌 · 우리 서버 아니고 인터넷에 있는 주소록
  3. 웹 서버 · t-box 앱요청을 받아 처리하는 우리 프로그램 · HTTPS로 암호화되어 오갑니다
  4. 데이터베이스파일 정보 · 사용자 · 감사 로그를 저장 · 만들고·읽고·고치고·지움(CRUD)
  5. 파일 저장소실제 업로드된 파일을 보관
충님의 설명

주소창에 도메인을 입력해도, 요청이 곧바로 우리 앱에 닿는 건 아닙니다. 먼저 DNS가 도메인(예: study.tla.so)을 실제 서버 주소(IP)로 바꿔줘요.

이 DNS는 우리 서버 안에 있지 않습니다. 인터넷 곳곳에 흩어진 “주소록 서버”예요. 도메인을 등록한 곳(Cloudflare, AWS Route 53, 가비아 등)이 “이 도메인 = 이 IP”라는 기록을 관리하고, 브라우저는 보통 통신사(ISP)공용 DNS(예: 8.8.8.8)에 물어서 그 IP를 받아옵니다.

IP를 알아낸 뒤에야 그 서버의 t-box 앱이 요청을 처리합니다. 이때 앱은 데이터를 만들고(Create)·읽고(Read)·고치고(Update)·지우는데(Delete), 이 네 가지를 묶어 CRUD라고 불러요. 파일 정보·기록은 데이터베이스에, 실제 파일은 파일 저장소에 두고 CRUD 합니다. 통신은 HTTPS로 암호화되고요.

핵심 순서 — 도메인을 IP로 찾고(DNS·외부 서비스) → 그 서버의 앱이 요청을 처리하고 → 데이터를 만들고·읽고·고치고·지웁니다(CRUD · DB·파일 저장소).

0:25 – 0:50 실습 02

터미널에 Claude Code 설치

오늘 프롬프트는 전부 Claude Code에 붙여넣음. 터미널 창 2개 필요함 — 하나는 Claude Code용, 하나는 명령어 입력용.

충님의 설명

Claude Code는 터미널(명령어 창)에서 바이브 코딩을 할 수 있는 AI 코딩 에이전트 도구예요. 오늘의 프롬프트는 전부 여기에 붙여넣습니다. 설치는 명령어 한 줄이면 끝나고, 처음 실행하면 뜨는 로그인 안내는 충님이 알려드립니다.

작업 폴더는 /var/www/html을 씁니다. 그런데 지금 VM엔 웹서버가 없어서 이 폴더가 아직 없어요. 그래서 sudo로 폴더를 만들고 내 계정 소유로 바꾼 다음 그 안에서 작업합니다.

그런데 문제가 하나 있어요. Claude Code가 설치 명령을 대신 실행할 때 sudo가 비밀번호를 물으면, AI는 비밀번호를 입력할 수 없어서 거기서 멈춰버립니다. 그래서 시작 전에 “이 실습 계정은 비밀번호 없이 sudo를 쓸 수 있게” 한 번 설정해 둘 거예요.

이 설정도 직접 외울 필요 없어요. Claude Code에게 명령어를 물어보고, 받은 걸 터미널에 붙여넣는 방식으로 해봅니다.

그래서 오늘은 터미널 창을 2개 띄워두고 씁니다. 하나는 Claude Code 전용, 다른 하나는 명령어 입력용이에요. 한 창에서 번갈아 하면 Claude Code를 껐다 켰다 해야 해서 번거롭거든요.

①–①–③ 터미널 2개를 열고 시작
터미널 A Claude Code 전용 AI에게 요청하는 창. 한번 켜두면 계속 켜둡니다.
터미널 B 명령어 입력용 설치·git·확인 명령을 직접 붙여넣는 창.

SSH로 접속했다면 창을 하나 더 열어 같은 VM에 한 번 더 접속하면 됨. 아래 ①②는 터미널 B, ③은 터미널 A에서 실행함.

B · 1) 설치 · Claude Code (명령어 한 줄)
curl -fsSL https://claude.ai/install.sh | bash
B · 2) 폴더 · 작업 폴더 만들고 내 소유로 바꾸기
sudo mkdir -p /var/www/html
sudo chown -R $USER /var/www/html
A · 3) 실행 · 그 폴더에서 Claude Code 켜기
cd /var/www/html
claude

claude 처음 실행하면 로그인 안내가 나옴. 로그인한 뒤(또는 /login) 프롬프트 창에 한글로 요청 입력하면 됨. 터미널 B도 cd /var/www/html 해두면 편함.

sudo
“관리자 권한으로 실행”이란 뜻임. 시스템 폴더 만들거나 프로그램 설치할 땐 권한이 필요해서 명령 앞에 붙임. 비번 물으면 충님이 알려준 거 입력해 — 아래 ④에서 안 묻게 설정함.
sudo chown -R $USER /var/www/html
/var/www/html 폴더와 그 안의 모든 것(-R)의 소유자를 지금 나($USER)로 바꿉니다. 이래야 앞으로 sudo 없이도 그 폴더에서 자유롭게 파일을 만들고 지울 수 있어요.
④ sudo 비밀번호 묻지 않게 설정 — AI에게 물어서 직접 하기

첫 바이브 코딩 연습임. 터미널 A(Claude Code)에 아래 프롬프트 붙여넣어 명령어를 받고, 그걸 터미널 B에 붙여넣어 직접 실행함.

A · 참가자 프롬프트 · Claude Code에 붙여넣기
지금 이 리눅스 계정이 sudo를 쓸 때 비밀번호를 묻지 않도록 설정하고 싶어.
교육용 실습 VM이고, 내가 관리자 권한을 가지고 있어.

- visudo로 문법 검사를 하면서 /etc/sudoers.d/ 아래에 파일을 만드는 방식으로 알려줘
- 내 계정 이름은 직접 확인해서 넣어줘 (whoami)
- 실행할 명령어를 복사해서 쓸 수 있게 알려주고, 설정이 잘 됐는지 확인하는 방법도 알려줘

명령은 네가 실행하지 말고, 내가 터미널에 붙여넣어 직접 실행할게.

왜 “직접” 실행하냐? sudo 권한 설정은 시스템에서 가장 조심해야 할 작업 중 하나임. AI가 준 명령을 한 번 읽어보고 내 손으로 실행하는 습관이, 오늘 배울 “AI에게 맡기되 검증한다”의 첫 연습임.

받은 명령을 터미널 B에 붙여넣어 실행한 뒤 아래로 확인함. OK 나오면 성공.

B · 확인 · 비번 없이 sudo 되는지
sudo -n true && echo "OK" || echo "아직 비밀번호를 묻습니다"
0:50 – 1:30 실습 03

보안을 고려하지 않고 만든 t-box 실행

오늘은 먼저 부숴봄. 충님이 미리 만들어 둔 보안을 고려하지 않은 파일 공유 앱을 각자 VM에 올리고 내 도메인으로 접속되게 만듦. 이게 뒤 해킹 실습 대상임.

충님의 설명

보통은 “만들고 → 고친다” 순서로 배우지만, 오늘은 반대로 갑니다. 먼저 보안을 고려하지 않은 서비스를 직접 공격해보고, “아, 이래서 위험하구나”를 몸으로 느낀 다음에 “그럼 제대로 만들려면?”을 이야기할 거예요.

이 앱은 순수 PHP + PostgreSQL로 만든 아주 작은 파일 공유 앱입니다. 로그인·권한·검증이 일부러 다 빠져 있어요. 저장소에 설치 안내서(INSTALL.md)가 들어 있어서, 코드를 내려받은 뒤 Claude Code에게 “INSTALL.md 읽고 설치해줘”라고만 하면 됩니다.

① 코드 내려받기

터미널 B에서 코드를 /var/www/html에 받음. (Claude Code 돌아가는 A는 그대로 둠.)

B · clone · 보안 고려하지 않은 t-box 코드
cd /var/www
sudo rm -rf html
sudo git clone https://git2.tla.so/hardline7/t-box-sample.git html
sudo chown -R $USER /var/www/html
cd /var/www/html

코드를 새로 받았으니 터미널 A에서도 cd /var/www/html 다시 입력 필요함. 안 하면 Claude Code가 옛 폴더를 봄.

② 설치는 Claude Code에게 통째로 맡기기

저장소 안에 INSTALL.md라는 설치 안내서가 들어 있음. 명령어를 하나씩 칠 필요 없이, 터미널 A에 아래 한 줄만 붙여넣으면 Claude Code가 웹서버·DB·nginx 설정까지 알아서 해줌.

A · 참가자 프롬프트 · 설치 맡기기
/var/www/html 의 INSTALL.md 를 읽고,
t-box가 내 VM에서 잘 실행되도록 설치해줘.
내 도메인은 "내이메일앞자리.tla.so" 야.
설치가 끝나면 브라우저로 접속되는지 확인하는 방법도 알려줘.

중간에 sudo 비번을 안 물어야 안 멈춤 — 그건 앞 단계(sudo 설정)에서 이미 처리했음.

확인 질문

내 도메인으로 접속하면 파일 목록(5개)이랑 업로드 폼 뜨냐? 위쪽 역할 전환 박스에서 Admin/Employee/Guest 바뀌냐?

1:40 – 2:20 해킹 타임 04

해킹 타임 1 · 프론트 권한 우회 & XSS

공격 기술 학습이 아님. 잘못 만든 서비스가 왜 위험한지 직접 체감하는 시간임.

내 VM의 교육용 t-box에서만. 외부·회사 실제 시스템·타 참가자 VM 금지.

공격 대상은 이미 준비돼 있음

설치할 때 schema.sql예시 파일 5개를 이미 넣어놨음. 따로 업로드할 필요 없이 바로 시작하면 됨.

파일명접근 레벨
회사소개.txt · 제품안내.txtpublic
사내공지.txt · 회의록.txtinternal
급여명세_2026.txtadmin-only ← 뒤에서 “안 보여야 하는데 보이는” 주인공

목록이 비어 있으면 설치가 덜 된 거임 → INSTALL.md의 DB 단계를 다시 실행.

취약점 A · 숨겨둔 삭제 버튼을 되살려 눌러보기

Employee에겐 삭제 버튼이 화면에서 숨겨져 있을 뿐, 버튼 자체는 브라우저 안에 그대로 있음. 숨긴 걸 다시 보이게 만들어 눌러봄.

① Admin으로 보면 admin01 (Admin)
역할 전환 · Admin ▾
ID파일명접근 레벨동작
1회사소개.txtpublic받기 삭제
3사내공지.txtinternal받기 삭제
5급여명세_2026.txtadmin-only받기 삭제
  • 1Admin이라 삭제 버튼 보이고 admin-only 파일(급여명세)도 목록에 있음. 정상임.
② Employee로 바꾸면 employee01 (Employee)
역할 전환 · Employee ▾
ID파일명접근 레벨동작
1회사소개.txtpublic받기 — 삭제 버튼만 숨김
3사내공지.txtinternal받기 — 삭제 버튼만 숨김
5급여명세_2026.txtadmin-only받기 — 삭제 버튼만 숨김
  • 2Employee인데 삭제 버튼만 사라졌을 뿐, 급여명세(admin-only)까지 그대로 보이고 “받기”도 눌립니다. 화면만 손봤을 뿐 서버는 아무도 안 막고 있어요. 여기서부터 실습 시작.
  1. Employee 계정으로 전환 → 목록에 삭제 버튼이 안 보이는 것 확인
  2. F12를 눌러 개발자도구 열기 → Elements(요소) 탭 선택
  3. 왼쪽 위 화살표 아이콘(Ctrl+Shift+C)을 켜고 파일 목록의 한 줄을 클릭 → 그 줄의 HTML로 이동
  4. 그 근처에서 삭제 버튼 태그를 찾습니다. style="display:none"이나 hidden, class="hidden"이 붙어 있을 거임
  5. 그 부분을 더블클릭해서 지우고 Enter화면에 삭제 버튼이 나타납니다
  6. 나타난 삭제 버튼을 클릭 → 파일이 진짜로 삭제되는지 확인
③ 개발자도구 · Elements(요소) 탭에서 보이는 모습
<td class="actions">
  <a class="btn btn-ghost" href="api/download.php?id=3">받기</a>
  <button class="btn btn-danger js-delete" data-id="3"
          style="display:none">삭제</button>
</td>
  • 3버튼은 지워진 게 아니라 그대로 있음. 빨갛게 칠한 style="display:none"더블클릭해서 지우고 Enter 쳐.
④ 지우자마자 버튼이 나타납니다 여전히 employee01
3사내공지.txtinternal받기 삭제
// 삭제 버튼을 누르면 콘솔에 찍히는 서버 응답
{
  "ok": true,
  "deleted": "사내공지.txt",
  "by": "employee01 (Employee)",
  "note": "서버가 권한을 확인하지 않았습니다"
}
  • 4Employee가 눌렀는데 서버가 그대로 삭제함. 서버는 “누가 보냈는지” 확인조차 안 함.

방금 무슨 일이 일어난 거임? 서버를 해킹한 게 아니라 내 브라우저 화면을 고쳤을 뿐임. 그런데 서버는 그 요청을 그대로 받아서 파일을 지움. 화면은 사용자 편의일 뿐 보안 장치가 아니라는 증거임.

버튼을 못 찾겠으면 콘솔에서 API를 직접 불러도 결과는 같음. 파일 ID(id=3)는 목록에 보이는 번호로 바꿔야 함 — Network 탭에서 실제 삭제 요청 주소 확인 가능함.

DevTools Console · 삭제 요청 직접 호출
fetch("api/files.php?id=3", { method: "DELETE" })
  .then((res) => res.json())
  .then(console.log);
붙여넣기 안 될 거임 — 이렇게 풀어

콘솔에 코드를 처음 붙여넣으면 브라우저가 경고 띄우고 막음. “모르는 코드를 붙여넣게 해서 계정을 뺏는 사기”를 막으려는 장치임. 아래 순서로 한 번만 풀어.

  1. F12Console(콘솔) 탭으로 이동
  2. 붙여넣기를 시도하면 “이해하지 못했거나 직접 검토하지 않은 코드는 붙여넣지 마세요…” 경고가 뜹니다
  3. 콘솔에 아래 문구를 직접 타이핑하고 Enter
    한글 브라우저붙여넣기 허용 영문 브라우저allow pasting 복사·붙여넣기 말고 손으로 쳐야 합니다. 둘 중 어느 걸 쓸지는 화면에 뜬 경고문 마지막 줄에 적혀 있어요.
  4. 이제 위 코드를 붙여넣고 Enter → 파일이 삭제되는지 확인

이 경고가 왜 있는지 기억해 둬. 실제로 “이 코드를 콘솔에 붙여넣으면 이벤트 당첨”처럼 속여서 계정을 탈취하는 공격(셀프 XSS)이 흔함. 오늘처럼 내가 만든 실습 앱 아니면, 남이 준 코드를 콘솔에 붙여넣지 마.

취약점 B · 권한 없는 자료가 그대로 보이고, 받아지기까지 함

Guest로 바꿔봄. 그래도 관리자 전용 급여명세_2026.txt가 목록에 보이고 “받기”를 누르면 실제로 내려받아짐. 화면에서 숨기지도 않은, 가장 노골적인 정보 유출임.

원인은 서버임. 개발자도구 Network 탭에서 api/files.php 응답을 열면 서버가 역할과 상관없이 모든 파일을 통째로 내려주는 게 보임.

  1. 위쪽 역할 전환을 Guest로 바꾸고 → 급여명세 파일이 보이는지 확인
  2. 그 줄의 “받기”를 눌러 실제로 내려받아지는지 확인
  3. F12Network 탭 → 새로고침 → files.php 응답에 admin-only가 있는지 확인
Network 탭 · api/files.php 응답 요청자: guest01
{
  "user": { "name": "guest01", "role": "Guest" },
  "files": [
    { "id": 1, "original_name": "회사소개.txt",  "access_level": "public" },
    { "id": 3, "original_name": "사내공지.txt",  "access_level": "internal" },
    { "id": 5, "original_name": "급여명세_2026.txt", "access_level": "admin-only" }
  ]
}
  • !Guest 요청인데 서버가 admin-only 파일까지 다 내려줌. 화면 필터가 있든 없든 권한 없는 데이터를 서버가 내려준 순간 이미 유출임. api/download.php?id=5로 내용까지 받아짐.
취약점 C · 파일명/설명이 그대로 실행되는 XSS

파일명이나 설명에 아래 값을 넣고 목록 화면으로 가면, 값이 글자가 아니라 코드로 실행됨.

XSS 테스트 · 기본
<script>alert('나는 해커다!! 이 서비스는 해킹됐다!!')</script>
XSS 테스트 · script가 필터될 때
<img src=x onerror="alert('나는 해커다!! 이 서비스는 해킹됐다!!')">
업로드할 때 · 설명 칸에 붙여넣음
파일 선택 · memo.txt <img src=x onerror="alert('나는 해커다!!')"> public ▾ 업로드
  • 1설명은 그냥 글자일 뿐인데 서버가 검사 없이 저장하고 화면이 그대로 HTML로 출력함.
목록 화면으로 가면 · 글자가 아니라 코드로 실행됨
이 페이지 내용:
나는 해커다!!
이 서비스는 해킹됐다!!
확인
  • 2내가 올린 파일을 다른 사람이 목록에서 보기만 해도 그 사람 브라우저에서 코드가 실행됨. 알림창 대신 쿠키를 훔쳐 보내는 코드였으면 계정 넘어감.
확인 질문 & 정답 방향

화면엔 삭제 버튼이 없었는데 왜 삭제됐을까요? 이 문제를 어디서 막아야 할까요?

→ 서버에서 사용자 역할을 확인 · DB의 접근 레벨과 역할을 비교 · 실패한 시도도 감사 로그에 남긴다.

2:20 – 2:50 해킹 타임 05

해킹 타임 2 · SSRF와 방어 설계

t-box의 “URL로 파일 가져오기” 기능을 공격해, 서버 안의 진짜 파일을 URL 한 줄로 꺼내 보는 걸 직접 확인함.

충님의 설명

t-box에는 URL을 넣으면 서버가 그 주소로 접속해 내용을 가져오는 기능이 있습니다. 이걸 이렇게 생각해보세요 — 서버는 “뭐든 가져다주는 심부름꾼”입니다. 그런데 이 심부름꾼은 사장실·금고에도 들어갈 수 있어요. 외부인인 내가 못 가는 곳을, 서버를 시켜서 대신 가져오게 만드는 것 — 이게 SSRF입니다.

내 노트북에서 file:///etc/passwd를 열면 내 파일이 열립니다. 하지만 서버에게 그 주소를 던지면 서버의 파일이 열려요. 지금부터 그걸 직접 해봅니다.

직접 공격 · 서버 내부 파일을 훔쳐보기

t-box 아래쪽 “URL로 파일 가져오기” 칸에 아래 주소를 붙여넣고, 검사 방식을 취약한 검사로 두고 검사를 눌러봄.

공격 URL · 서버의 계정 목록 파일
file:///etc/passwd
취약한 검사로 넣으면 · 서버 안 파일이 그대로 나옴
file:///etc/passwd 취약한 검사 ▾ 검사

허용됨 ✅ 검증 없이 서버가 그대로 가져옴

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
postgres:x:114:120:PostgreSQL admin:/var/lib/postgresql:...
… (이하 생략)
  • !이건 서버 안에 있는 진짜 파일임. 리눅스 계정 목록이 통째로 털린 거예요. 내 노트북에선 절대 못 보는 남의 서버 내부 파일을, URL 한 줄로 꺼냈음.

이번엔 검사 방식을 방어된 검사로 바꾸고 같은 주소로 다시 검사 눌러봄.

방어된 검사로 바꾸면 · 막힘
file:///etc/passwd 방어된 검사 ▾ 검사

차단됨 ⛔ http/https가 아니라서 거부 — 파일 내용이 안 나옴

  • 같은 주소인데 방어된 검사는 아무것도 안 내줌. 차이는 딱 하나 — 서버가 주소를 검사하느냐 안 하느냐임.

여유 되면 http://169.254.169.254/latest/meta-data(클라우드 서버라면 관리자 키가 나오는 주소)나 아래 표의 다른 내부 주소도 취약한 검사로 넣어봄.

허용 / 차단 URL
URL판정
https://example.com/report.pdf허용
http://localhost/admin차단
http://127.0.0.1:3000차단
http://0.0.0.0:3000차단
http://10.0.0.5/secret차단
http://172.16.0.10/secret차단
http://192.168.0.10/secret차단
http://169.254.169.254/latest/meta-data차단
file:///etc/passwd차단
ftp://example.com/file.txt차단
그럼 방어된 검사는 뭘 하나

숙제로 만들 제대로 된 t-box는 아래처럼 막아야 함. 지금 앱의 “방어된 검사”가 이걸 하고 있음.

  • http/https만 허용
  • DNS 해석 후 IP 검사 · 사설 IP·localhost·link-local 차단
  • 리다이렉트 후 최종 주소 재검사
  • 요청 시간 제한 · 응답 크기 제한
  • 차단 이벤트를 감사 로그에 기록
3:00 – 3:20 개념 06

왜 이렇게 쉽게 뚫렸을까 · 제대로 된 서비스란

방금 부순 걸 정리함. “그럼 제대로 만들려면 뭐가 달라야 하나”를 짚고, 다음 단계에서 설계로 옮김.

우리가 방금 뚫은 것들
무엇이 뚫렸나진짜 원인제대로라면
권한 없이 파일 삭제화면에서 버튼만 숨기고 서버는 검사 안 함서버가 요청자의 역할을 확인
숨긴 파일이 다 보임서버가 모든 파일을 내려주고 화면에서만 필터권한 없는 데이터는 애초에 안 내려줌
파일명이 코드로 실행(XSS)입력값을 그대로 화면에 출력출력할 때 글자로 안전하게 이스케이프
내부 주소 접근(SSRF)사용자가 준 URL을 검증 없이 서버가 요청http/https만·사설IP 차단·최종주소 재검사
누가 뭘 했는지 모름기록(감사 로그)이 아예 없음주요 행동·차단 이벤트를 로그로 남김
화면에서 버튼을 숨기는 것은 보안이 아니다. 서버가 권한을 확인해야 보안이다.
충님의 설명

방금 우리가 한 공격은 대단한 기술이 아니었어요. 대부분 클릭 몇 번, 주소 하나였습니다. 그런데도 파일이 지워지고, 남의 자료가 보이고, 코드가 실행됐죠. 이게 보안을 나중으로 미룬 서비스의 실제 모습입니다.

공통점이 하나 있어요. “화면에서 막으면 되겠지”라고 생각한 겁니다. 하지만 화면은 사용자 손 안에 있어요. 진짜 방어선은 서버입니다. 그리고 방어는 기능을 만들 때 같이 넣어야지, 다 만든 뒤에 얹으려면 이미 늦습니다.

좋은 서비스는 “되게 만드는 것”에서 끝나지 않습니다. “나쁘게 쓰려는 사람”까지 생각하는 것입니다.

3:20 – 3:55 실습 07

제대로 만들려면 · PRD와 아키텍처를 AI와 설계

방금 겪은 취약점이 처음부터 안 생기게, 무엇을 만들지(PRD)와 어떻게 만들지(아키텍처)를 AI와 상의해 문서로 남김. 이 문서가 숙제 출발점임.

충님의 설명

많은 사람이 AI에게 바로 “앱 만들어줘”라고 합니다. 그러면 방금 본 것처럼 보안이 빠진 게 나올 수도 있어요. 그래서 만들기 전에 무엇을·어떻게 만들지 먼저 정리합니다 — 그게 PRD아키텍처예요.

핵심은 보안을 요구사항에 처음부터 적어 넣는 겁니다. “권한은 서버에서 확인”, “입력값은 안전하게 출력”, “주요 행동은 로그로” 같은 걸 PRD에 못 박아두면, AI도 그에 맞춰 만들어요.

그리고 프롬프트에서 “적절히·안전하게 같은 모호한 말을 쓰지 말고 측정 가능한 조건으로 써라”, “각 요구사항에 ID를 붙이고, 설계가 그 ID를 어떻게 만족하는지 추적성을 표시해라”처럼 작성 규칙까지 지시하면, 목차만 채운 문서가 아니라 실제로 개발팀에 넘길 수 있는 문서가 나옵니다. 아래 프롬프트가 그렇게 짜여 있어요.

좋은 바이브 코딩은 구현 요청 전에 설계 대화를 먼저 합니다. 그리고 그 결과를 문서로 남겨 계속 참조합니다.

A · 참가자 프롬프트 · PRD 만들기 (보안 포함)
[역할] 너는 B2B SaaS를 여러 번 출시한 시니어 프로덕트 매니저다.
[과제] 사내 파일 공유 서비스 "t-box"의 PRD를 실제 개발팀에 넘길 수 있는
수준으로 작성한다. 나는 방금 이 서비스의 "보안을 고려하지 않은 버전"을
직접 공격해봤고, 이번엔 처음부터 제대로 정의하려 한다.

[작성 원칙 — 반드시 지킬 것]
- 모호어 금지: "적절히", "안전하게", "빠르게", "필요시" 같은 말은 쓰지 말고
  전부 측정 가능한 수치·조건으로 바꿔 써라. (예: "빠르게" → "p95 < 300ms")
- 모든 기능 요구사항에는 고유 ID(FR-01…)와 우선순위(P0/P1/P2)를 붙여라.
- 모든 유저 스토리에는 Given/When/Then 형식의 인수조건을 최소 2개씩 달아라.
- 각 요구사항은 "구현했는지 테스트로 확인 가능한가?"를 통과해야 한다.
  통과 못 하면 다시 써라.
- 표가 명확한 곳(권한 매트릭스, 접근 레벨, 마일스톤)은 마크다운 표로 써라.
- 근거 없는 숫자를 지어내지 말고, 가정은 "가정:"으로 명시하고 근거를 붙여라.

[분량/형식] 마크다운. 각 섹션에 번호. 최소 이 정도 깊이로:

1. 문서 정보 — 버전, 작성일(가정), 상태, 용어 정의(Glossary)
2. 개요 — 1줄 설명 / 해결할 문제(현재의 불편을 구체 시나리오로) /
   목표를 측정지표로(예: "공유 요청 처리 시간 X분 → Y초") / Non-goals 명시
3. 페르소나 — Admin / Manager / Employee / Guest 각각의 목표·권한·불안요소
4. 유저 스토리 & 인수조건 — 역할별로 총 12개 이상, 각 스토리에
   "As a / I want / So that" + Given/When/Then 인수조건 2개 이상
5. 기능 요구사항 — FR-ID·우선순위 포함. 최소 다음을 다뤄라:
   업로드(재개/중복/크기제한), 목록(검색·정렬·페이지네이션·필터),
   미리보기/다운로드, 삭제(휴지통/영구), 공유(링크·만료·접근레벨 변경)
6. 권한 모델 — 역할 4종 × 행동(업로드/조회/다운로드/공유/삭제/관리)의
   권한 매트릭스 표 + 접근 레벨(public/internal/team/admin-only) 정의와
   "누가 무엇을 볼 수 있는가" 규칙을 문장으로 못 박기
7. 보안 요구사항 — 각 항목을 검증 가능한 요구문으로(SR-ID 부여):
   서버측 인증·인가, 권한 없는 데이터는 응답에서 원천 제외,
   출력 인코딩(XSS)·CSRF 토큰, 업로드 크기/확장자/MIME 검증 및
   추측 불가 저장명, SSRF 방어(스킴 화이트리스트·사설망 차단·리다이렉트 재검사),
   전 구간 감사 로그, 세션·비밀번호·전송(TLS) 정책
8. 비기능 요구사항 — 성능(동시 사용자·파일 수 가정과 p95 목표),
   확장성, 가용성(SLO), 관측성(로그·지표·알림), 접근성(WCAG), 국제화
9. 데이터 모델 개요 — 엔티티(User, File, Permission/ACL, AuditLog, Session)와
   핵심 필드·관계
10. 데이터 수명주기 & 보관 정책 — 파일/로그/세션별 보관 기간(리텐션),
    삭제 방식(소프트 삭제 → 휴지통 → 영구 파기), 파기 시 백업본 처리,
    개인정보/민감정보 취급 원칙
11. 백업·복구·비즈니스 연속성 (필수) — 다음을 수치로 정의:
    - RPO(허용 데이터 손실 시간)와 RTO(목표 복구 시간)를 정하고 근거 제시
    - 백업 대상(DB / 업로드 파일 / 설정·시크릿)별 주기·방식(전체/증분)·
      보관 세대수·보관 위치(오프사이트 포함)
    - 백업 암호화 및 접근 통제(백업본도 유출 자산이라는 관점)
    - 복구 절차(런북)와 "복구 훈련을 언제/어떻게 검증할지"
    - 랜섬웨어·실수 삭제·DB 손상 각 시나리오별 대응
12. 감사 로그 명세 — 어떤 이벤트를(성공·실패·차단) 어떤 필드로 남길지 표.
    로그 보관 기간, 로그에 민감정보를 남기지 않는 규칙, 위·변조 방지
13. 운영 — 모니터링 지표와 알림 임계값, 장애 등급/에스컬레이션,
    정기 점검 항목, 배포·롤백 전략
14. 릴리스 계획 — 마일스톤(M1 MVP / M2 보안하드닝 / M3 성능·운영)별
    포함 FR-ID와 완료 정의(Definition of Done)
15. 성공 지표 — 활성 사용자, 업로드 성공률, 권한 위반 차단 건수,
    백업 성공률·복구 훈련 통과율 등
16. 리스크·의존성·미해결 질문(Open Questions)

마지막에 "이 PRD가 처음의 취약한 버전과 무엇이 달라졌는지" 3줄 요약.
전체를 PRD.md 파일로 저장해줘.
A · 참가자 프롬프트 · 아키텍처 상담
[역할] 너는 t-box를 실제로 구현할 시니어 백엔드 엔지니어이자
보안 리뷰까지 하는 테크리드다.
[과제] 방금 만든 PRD.md를 읽고, 그 요구사항(FR-/SR- ID)을 만족하는
아키텍처 설계 문서를 작성한다. 이 문서만 보고 다른 개발자가
동일하게 구현할 수 있어야 한다.

[제약]
- 스택: 순수 PHP(프레임워크 없이) + PostgreSQL + nginx + php-fpm,
  파일은 서버 디스크 저장. 도메인 "내이메일앞자리.tla.so".
- 새 요구사항을 지어내지 말고, 각 설계 결정이 PRD의 어느 FR-/SR-를
  만족시키는지 괄호로 추적성(traceability)을 표시해라.
- 설계 결정에는 이유와 대안을 짧게 남겨라(왜 이 방식? 안 쓴 대안은?).
- 다이어그램은 mermaid 코드블록으로 그려라(렌더 가능해야 함).

[포함할 내용]
1. 아키텍처 개요 — 시스템 컨텍스트 다이어그램(mermaid),
   구성요소별 책임(브라우저 / nginx / php-fpm / PHP 앱 계층 /
   PostgreSQL / 파일 저장소)과 신뢰 경계(trust boundary) 표시
2. 요청 시퀀스 — 업로드 / 목록 / 다운로드 / 삭제 / 공유 각각을
   mermaid sequenceDiagram으로. 각 시퀀스에 "인증 확인 → 인가(역할×접근레벨)
   확인 → 실행 → 감사 로그" 단계를 명시하고, 인가 실패 시 403 분기까지
3. 애플리케이션 계층 구조 — 요청이 통과하는 계층(라우팅 → 입력검증 →
   인증 미들웨어 → 인가 검사 → 도메인 로직 → 데이터 접근 → 출력 인코딩)과
   각 계층의 책임. 권한 검사가 "한 곳(서버)"에서만 일어나도록 하는 구조
4. 데이터 모델 — users, files, permissions/ACL, audit_logs, sessions의
   DDL 수준 스키마(컬럼·타입·제약·인덱스·FK)와 ER 다이어그램(mermaid).
   접근 레벨/역할을 DB에서 표현하는 방식과 권한 조회 쿼리 예시
5. 인가 설계 — 목록 조회 시 "권한 있는 파일만" 내려주는 쿼리 전략,
   단건 접근(다운로드/삭제) 시 소유·역할·접근레벨 검사 지점(IDOR 방지)
6. 보안 설계 — 위협 모델을 간단한 표로(자산 / 위협 / 대응).
   공격면별 방어 배치: 입력검증·출력 인코딩(XSS)·CSRF·업로드 검증
   (크기/확장자/MIME/추측불가 저장명/웹루트 밖 저장)·SSRF 방어·
   전송 암호화·세션 관리·비밀정보(.env) 취급
7. API 명세 — 엔드포인트별 경로 · 메서드 · 요청/응답 스키마 ·
   필요 권한 · 에러 코드(401/403/404/413/422). 표로
8. 파일 저장 전략 — 저장 경로(웹루트 밖), 저장 파일명 규칙,
   다운로드 시 앱을 거쳐 스트리밍하는 이유, 직접 URL 접근 차단
9. 백업·복구 설계 (필수) — PRD의 RPO/RTO를 만족하는 구체적 방법:
   - 백업 대상별 전략: PostgreSQL(pg_dump/WAL 아카이빙 중 선택과 이유),
     업로드 파일 디렉터리, .env·nginx 설정
   - 주기·보관 세대·보관 위치(로컬 + 오프사이트), 백업 파일 암호화 방식
   - 백업 자동화(cron 예시)와 성공/실패 알림
   - 복구 런북: DB만 손상 / 파일만 손실 / 서버 전체 재구축 각 시나리오별
     명령 수준 절차와 예상 소요 시간(RTO와 대조)
   - 복구 검증 방법(정기 리허설, 체크섬 비교)
10. 코드 구조 — 실제 폴더/파일 트리와 각 파일 책임(한 줄씩)
11. 배포/운영 — nginx 서버블록 요지(php-fpm 연동, 정적/동적 분리,
    .env·.git·백업파일 노출 차단), .env로 관리할 값 목록,
    로그 위치·로테이션, 헬스체크 엔드포인트, 배포·롤백 절차
12. 관측성 — 무엇을 로그/지표로 남기고 어떤 조건에 알림을 보낼지
13. 미결정 사항과 향후 확장(용량 증가 시 오브젝트 스토리지 전환 등)

전체를 ARCHITECTURE.md 파일로 저장해줘.
A · 참가자 프롬프트 · 설계 검토받기
[역할] 너는 침투 테스트와 시큐어 설계 리뷰를 전문으로 하는
애플리케이션 보안 엔지니어(AppSec)다. "통과시켜주는 리뷰"가 아니라
공격자 관점으로 이 설계를 실제로 깨보는 게 목적이다.

[입력] PRD.md 와 ARCHITECTURE.md 를 모두 읽고 시작해라.

[1) 자산·신뢰경계 식별]
보호 자산(파일 원본, 파일 메타데이터, 사용자 계정/세션, 감사 로그,
백업본, .env의 비밀값)을 나열하고, 신뢰 경계(브라우저↔서버, 앱↔DB,
앱↔파일시스템, 운영자 접근)를 표시.

[2) STRIDE 위협 모델링]
각 구성요소·흐름에 Spoofing / Tampering / Repudiation /
Information Disclosure / Denial of Service / Elevation of Privilege
를 적용해 위협을 도출. 표로:
| ID | 자산 | 위협(STRIDE) | 공격 시나리오 | 영향 | 가능성 | 위험도 | 설계의 대응 | 미흡점 |

[3) 내가 실제로 뚫은 4가지 재검증 (반드시)]
프론트 권한 우회 / 권한 없는 데이터 노출 / 저장형 XSS(파일명·설명) /
SSRF(file:// 및 내부망 주소로 서버 내부 파일 유출).
각각 "어느 SR-ID·어느 흐름"이 막는지 명시하고, 우회 가능성을 다시 공격해봐라.

[4) 파일 공유 서비스 특화 위협 — 아래는 전부 점검]
- 접근제어: IDOR(파일 ID 조작), 수평/수직 권한 상승, 공유 링크 추측·만료 우회
- 업로드: 웹셸·실행파일, MIME 스푸핑, 압축폭탄, 경로 조작(../), 심볼릭 링크
- 다운로드: 경로 탐색으로 임의 파일 읽기, 인증 우회 직접 접근
- 인젝션: SQL / OS 커맨드 / 헤더 인젝션, 저장형·반사형 XSS
- 세션/인증: 세션 고정·탈취, CSRF, 브루트포스, 비밀번호·토큰 저장 방식
- SSRF: 리다이렉트 우회, DNS 리바인딩, 클라우드 메타데이터 접근
- 로깅: 민감정보 로깅, 로그 위·변조, 로그 인젝션
- 데이터 보호: 저장/전송 암호화, 백업본 유출, 시크릿(.env) 노출
- 가용성/복구: 백업 무결성, 랜섬웨어·삭제 사고 시 RPO/RTO 실현 가능성

[5) 방어 심층성·규정]
다층 방어(한 겹 뚫려도 다음이 막는지), 최소 권한, 안전한 기본값
(deny by default) 여부. OWASP Top 10 / OWASP ASVS 관점에서 빠진 항목 지적.

[6) 설계 품질]
요구사항 간 충돌·모호함, 빠진 엣지 케이스, 테스트로 검증 불가능한 요구사항.

[출력 형식]
발견마다: 제목 / 심각도(Critical·High·Medium·Low + 근거) /
공격 시나리오(재현 단계) / 영향 / PRD·아키텍처의 어디를 어떻게 고칠지(구체 수정안) /
검증 방법. 심각도 높은 순 정렬. 마지막에 "출시 전 반드시 막아야 할 Top 5".
과제 숙제 08

숙제 · 제대로 된 t-box를 만들어 오기

오늘 만든 PRD.md·ARCHITECTURE.md를 실제 명세로 삼아, 방금 뚫었던 취약점이 없는 파일 공유 서비스를 운영 가능한 수준으로 완성해 옴. AI와 만들되 검증은 내가 함.

과제 개요
목표PRD/아키텍처를 만족하는, 오늘의 4대 취약점이 없는 t-box를 완성
스택순수 PHP + PostgreSQL + nginx (프레임워크 없이)
제출물Git 서버(git2.tla.so) 내 저장소 — 코드 · README · 보안 자체점검 문서
방식AI와 기능 하나씩 만들고 내가 직접 공격해 검증 후 다음으로. 매 기능 커밋(한글)
단계별 로드맵 — 순서대로, 각 단계 끝에 커밋
  1. 1단계 · 뼈대와 DB — 스키마(users·files·permissions·audit_logs·sessions) 생성, 접속·설정을 .env로 분리
  2. 2단계 · 인증/세션 — 로그인, 세션 관리, 로그인 안 하면 아무것도 못 함
  3. 3단계 · 기본 기능 — 업로드 / 목록 / 다운로드 / 삭제 (아직 권한 없이 동작만)
  4. 4단계 · 서버 인가 — 모든 API에 역할×접근레벨 검사, 권한 없으면 403 + 목록·다운로드 응답에서 원천 제외 (IDOR 방지: 남의 파일 ID로도 못 받게)
  5. 5단계 · 입력/출력 안전 — 출력 인코딩(XSS), CSRF 토큰, SQL은 파라미터 바인딩
  6. 6단계 · 업로드 하드닝 — 크기·확장자·MIME 검증, 추측 불가 저장명, 웹루트 밖 저장 + 앱 거쳐 다운로드
  7. 7단계 · SSRF 방어 — (URL 가져오기 기능을 만들었다면) http/https만·사설망 차단·리다이렉트 재검사
  8. 8단계 · 감사 로그 — 성공/실패/차단 이벤트 기록, Admin만 열람
  9. 9단계 · 성능/운영 — 목록 검색·정렬·페이지네이션, 백업 스크립트(cron) + 복구 절차 README에

3~8단계는 각각 끝나면 바로 그 취약점을 스스로 공격해보고, 막히는 걸 확인한 뒤 커밋.

A · 참가자 프롬프트 · 구현 시작 (첫 프롬프트)
내가 만든 PRD.md와 ARCHITECTURE.md를 먼저 읽어줘. 이 문서가 명세야.

t-box를 순수 PHP + PostgreSQL로, 프레임워크 없이 만들 거야.
한 번에 다 만들지 말고 아래 단계 순서로, 각 단계가 끝나면
멈추고 내가 확인·커밋한 뒤 다음으로 넘어가자.

1) DB 스키마 + .env 분리
2) 로그인/세션
3) 업로드·목록·다운로드·삭제(동작만)
4) 서버 인가: 모든 API에 역할×접근레벨 검사(403), 목록·다운로드
   응답에서 권한 없는 건 원천 제외, 남의 파일 ID 직접접근(IDOR)도 차단
5) 출력 인코딩(XSS)·CSRF 토큰·SQL 파라미터 바인딩
6) 업로드 검증(크기·확장자·MIME·추측불가 저장명·웹루트 밖 저장)
7) (URL 가져오기 기능이 있으면) SSRF 방어
8) 감사 로그(성공·실패·차단), Admin만 열람
9) 목록 검색·정렬·페이지네이션 + 백업/복구 스크립트

각 단계마다: 무엇을 만들었는지 요약, 내가 확인할 방법,
한글 커밋 메시지 제안을 함께 줘. 지금은 1단계만 시작해.
A · 참가자 프롬프트 · 단계마다 자가 공격 검증
방금 만든 단계를 내가 직접 공격해서 검증하고 싶어.
이 단계에서 막아야 할 공격을 재현하는 방법을 알려줘 —
브라우저 개발자도구나 콘솔에서 내가 직접 해볼 수 있는 형태로.
그리고 "막히면 이런 결과, 안 막히면 이런 결과"를 미리 알려줘.
막히지 않으면 어느 파일 어느 줄을 어떻게 고쳐야 하는지 짚어줘.
(고치는 건 네가 하지 말고, 내가 읽고 판단해서 반영할게.)
완료 기준 (Definition of Done) — 이걸로 채점함

기능

보안 — 직접 공격해서 막히는 걸 증명

운영·제출물

가산점 (여유 되면)
제출 방법

완성 코드를 git2.tla.so의 내 저장소에 push. README(실행법)와 SECURITY.md(4대 공격 + 추가 위협을 어디서 어떻게 막았는지 + 직접 공격해 막힌 증거)를 반드시 포함. 커밋 히스토리로 단계별로 만든 과정이 보여야 함. 저장소·토큰·push 설정은 맨 아래 부록 참고.

3:55 – 4:00 마무리 09

마무리 · 오늘 잡은 감각

반나절 만에 리눅스 서버·터미널·Git·AI 에이전트·해킹·설계까지 다 겪음. 뭘 했는지 짚고, 오늘 핵심을 내 말로 정리함.

오늘 한 것 — 생각보다 많이 함
영역오늘 직접 한 것
리눅스 서버우분투 VM에 접속해 터미널로 작업 · sudo로 관리자 권한 · 폴더 만들고 소유권 변경 · 패키지 설치
웹 서비스 구조도메인 → DNS → 웹서버(nginx) → 앱 → DB·파일저장소 흐름 이해 · 내 도메인으로 서비스 띄움
Git저장소에서 코드 clone · 커밋과 push의 의미 · 토큰 발급과 .env로 비밀값 관리
AI 에이전트Claude Code 설치·로그인 · 터미널 2개로 작업 분리 · INSTALL.md를 읽혀 설치를 통째로 위임 · AI가 준 명령을 검토 후 내 손으로 실행
해킹 체험숨긴 버튼 되살려 삭제 · 권한 없는 자료 노출 확인 · XSS로 코드 실행 · SSRF로 서버 내부 파일 유출
설계PRD(유저스토리·권한매트릭스·보안·백업/RPO·RTO)와 아키텍처를 AI와 작성 · 보안 관점 검토까지 받음

개발 경험 거의 없이 시작해서 반나절에 여기까지 옴. 숙제로 남은 건 이 설계를 실제 서비스로 완성하는 것.

충님의 설명

오늘 반나절 만에 꽤 많은 걸 하셨습니다. 리눅스 서버를 만지고, Git을 쓰고, AI에게 설치를 맡기고, 직접 해킹까지 해보고, PRD와 아키텍처를 설계했어요. 개발 경험이 거의 없는 상태에서 여기까지 온 건 충분히 대단한 겁니다.

그런데 여기서 딱 하나만 오해하지 마세요. 오늘 한 건 맛만 본 수준입니다. PRD 쓰고 AI에게 보안 점검받는 건 기본이지 충분조건이 아니에요. 서버 자체 보안, OS와 nginx·PostgreSQL의 취약점, PHP 버전 문제, 아직 패치도 없는 제로데이 — 이런 게 전부 남아 있습니다.

그리고 AI로 개발 속도가 폭발한 만큼, 공격 기법도 똑같이 폭발하고 있습니다. 게다가 대부분의 보안 사고는 털린 줄도 모르는 상태예요. 조용히 빠져나가고 몇 달 뒤에 외부에서 알려줍니다. 그래서 만들고 끝이 아니라 주기적인 점검과 보안 업데이트가 운영 그 자체인 겁니다.

그리고 오늘 왜 설계부터 시작했는지 — 처음 설계가 잘못되면 기능을 붙일수록 누더기가 되고, 그 이음새마다 보안 구멍과 성능 문제가 터집니다. 나중엔 고치지도 버리지도 못하는 상태가 돼요. 설계에 쓴 30분이 나중에 몇 달을 아낍니다.

실제 작업물 시연 — 오늘 배운 게 실무에선 이렇게 쓰임

충님이 지금 만들고 있는 실제 서비스 t-work(약 90% 완성)를 직접 열어서 보여줌. 오늘 실습이 장난감이 아니라 진짜로 서비스를 만드는 방식이라는 걸 눈으로 확인하는 순서.

  1. CLAUDE.md — AI에게 프로젝트 규칙·컨벤션·주의사항을 미리 알려주는 문서. 이게 있으면 AI가 매번 헤매지 않고 프로젝트 스타일대로 만듦
  2. 실제 Git 커밋 히스토리 — 기능·버그수정·리팩터링이 어떤 단위로 쌓였는지, 커밋 메시지를 실제로 어떻게 쓰는지
  3. 실제 PRD·아키텍처 문서 — 오늘 만든 것과 같은 문서가 실무에서 어느 깊이로 쓰이고, 개발 내내 어떻게 참조되는지
착각하지 마 — 오늘 한 건 “찍먹”임

PRD 쓰고, 아키텍처 설계하고, AI한테 보안 점검받는 것 — 이건 기본이지 충분조건이 절대 아님. 오늘 다룬 4가지 취약점은 웹 보안의 입구일 뿐임. 실제 서비스를 운영하려면 아래가 전부 남아 있음.

오늘 안 다룬 것왜 위험한가
서버 자체 보안방화벽·SSH 설정·계정 관리·불필요 포트. 앱이 완벽해도 서버가 뚫리면 끝
OS·미들웨어 취약점리눅스·nginx·PostgreSQL에 계속 발견되는 취약점. 업데이트 안 하면 그대로 구멍
언어·프레임워크 취약점PHP 버전 자체의 보안 이슈, 쓰는 라이브러리의 알려진 취약점(공급망)
제로데이아직 패치가 없는 취약점. “최신으로 유지”해도 못 막는 게 있음
운영 보안비밀값 관리, 접근 권한 회수, 로그 감시, 백업본 보호, 내부자 위협

그리고 이것부터 명심해.

  • 1AI로 개발 속도가 폭발한 만큼, 공격 기법도 똑같이 폭발하고 있음. 작년에 안전했던 코드가 올해도 안전하다는 보장이 없음.
  • 2대부분의 보안 사고는 “털린 줄도 모르는” 상태임. 조용히 데이터가 빠져나가고, 몇 달 뒤에야 외부에서 알려줌. 그래서 감사 로그와 모니터링이 기능보다 중요할 때가 있음.
  • 3만들고 땡이 아님. 주기적인 점검과 보안 업데이트는 선택이 아니라 운영 그 자체임. 서비스가 살아있는 한 계속 해야 함.

왜 오늘 설계부터 시작했냐면. 처음 설계가 잘못되면 기능을 붙일수록 누더기 코드가 됨. 그 이음새마다 보안 구멍과 성능 문제가 생기고, 나중엔 고치자니 다 뜯어야 하고 두자니 계속 터지는 상황이 옴. 그때 가서 “처음부터 다시 만들자”는 비용이 제일 비쌈. 설계에 쓴 30분이 나중에 몇 달을 아낌.

AI가 코드를 대신 써주는 시대에, 사람이 할 일은 무엇을 만들지 정하고, 나온 결과를 의심하고 검증하고, 계속 지켜보는 것이다.
부록 참고

부록 · Git 치트시트 & 문제 해결

막히면 여기. 숙제 제출용 Git 준비, 자주 쓰는 명령, 흔한 에러 해결법.

숙제 제출용 · 내 Git 저장소에 push 하기

숙제(제대로 된 t-box)를 내 저장소에 올리려면 저장소와 토큰이 필요함.

  1. git2.tla.so에 로그인 → New Repository → 이름 t-box (README 체크 안 함, 빈 저장소)
  2. 프로필 → 설정 → 어플리케이션 → 액세스 토큰 관리 → 새 토큰 → 권한에서 repository = 읽기와 쓰기 → 생성 후 토큰 복사
  3. /var/www/html/.env에 계정·이메일·저장소주소·토큰을 넣고, Claude Code에 아래처럼 설정을 맡기기
A · 참가자 프롬프트 · git 연결
/var/www/html/.env 에 GIT_USERNAME, GIT_EMAIL, GIT_REPOSITORY, GIT_TOKEN이 있어.
이 값으로 git을 초기화하고, 이름·이메일을 설정하고,
원격 저장소 origin을 토큰이 포함된 주소로 연결해줘.
.env는 .gitignore에 넣어 커밋되지 않게 해줘.
커밋 메시지는 항상 한글로 제안해줘.

⚠ 토큰은 .env에만. AI 대화창에 토큰 값을 직접 붙여넣지 마.

GIT 자주 쓰는 명령

bash
git status              # 변경사항 확인
git add .               # 전체 스테이징
git commit -m "메시지"  # 저장
git push                # 서버로 올리기
git remote -v           # 원격 저장소 확인

FIX 흔한 에러

  • remote origin already exists
    git remote set-url origin <URL>
  • nothing to commit
    변경사항 없음 → git status로 확인
  • authentication failed
    계정·저장소 권한 확인, 토큰 재발급
A · 참가자 프롬프트 · 커밋 메시지 추천받기
지금 변경사항에 맞는 Git 커밋 메시지를 추천해줘.
한글로, 짧고 명확하게 3개 제안해줘.
나중에 봐도 무엇을 했는지 알 수 있는 문장으로.