t-box를 부숴보고, 제대로 다시 만든다
보안을 고려하지 않고 만든 사내 파일 공유 앱 t-box를 직접 공격해 “왜 위험한지”를 몸으로 느끼고 → AI와 함께 제대로 된 서비스를 설계한 뒤 → 그걸 완성해 오는 흐름. 코드 암기가 목적이 아니라, AI와 요구사항을 정리하고 결과를 검증하는 일하는 방식을 익히는 시간임.
HOW 이 화면 사용법
- 충님의 설명 들으며 위에서 아래로 순서대로 따라감.
- 각 단계 “지금 할 일” 체크하면 진행률 올라감.
- 프롬프트 카드는 복사 버튼으로 그대로 AI에 붙여넣음.
- 왼쪽 목차로 언제든 이동 · 현재 위치 표시됨.
GOAL 오늘 잡을 감각
- 보안을 고려하지 않은 서비스가 얼마나 쉽게 뚫리는지 직접 겪는다.
- 화면에서 숨기는 건 보안이 아니다 — 서버가 막아야 한다.
- 보안은 나중이 아니라 설계할 때부터 넣는다.
- AI에게 만들게 하고, 의심하게 하고, 검증한다.
실습 안전 수칙. 오늘의 모든 공격 실습은 본인 VM의 교육용 t-box 앱 안에서만 진행함. 외부 사이트, 회사 실제 시스템, 다른 참가자 VM 대상 금지. 허가되지 않은 스캔·자동화 공격 금지.
그리고 토큰·API 키·비밀번호는 AI 대화창에 절대 입력하지 마.
오프닝 · 오늘의 목표
오늘은 순서가 거꾸로임. 먼저 보안을 고려하지 않은 서비스를 직접 부숴보고, 그다음 “제대로 만들려면?”을 AI와 설계함.
충님의 설명 ›
오늘은 개발 문법을 외우는 시간이 아닙니다. 우리가 다룰 건 t-box라는 작은 파일 공유 서비스인데, 오늘은 먼저 보안을 고려하지 않고 만든 버전을 직접 공격해볼 겁니다. 클릭 몇 번으로 남의 파일이 지워지고, 숨긴 자료가 보이는 걸 눈으로 확인할 거예요.
그렇게 “왜 위험한지”를 몸으로 느낀 다음, AI와 함께 제대로 된 서비스를 설계합니다. 그걸 직접 완성해 오는 게 오늘의 숙제예요.
AI가 코드를 대신 써줄 수는 있지만, 무엇이 안전하고 쓸 만한 서비스인지는 사람이 판단해야 합니다.
- 부순다 — 보안을 고려하지 않은 t-box를 내려받아 실행하고, 직접 공격해본다
- 이해한다 — 왜 이렇게 쉽게 뚫렸는지, 제대로면 뭐가 달라야 하는지
- 설계한다 — 보안을 처음부터 넣은 PRD·아키텍처를 AI와 만든다
- 만들어 온다 — 제대로 된 t-box를 완성하는 게 숙제
브라우저에서 앱까지 · 전체 구조
도메인을 입력하면 요청이 어떤 길을 거쳐 우리 앱에 도달하는지 파악함.
-
브라우저사용자가 주소를 입력하고 화면을 보는 곳
-
도메인 · DNS도메인을 실제 서버 IP로 바꿔줌 · 우리 서버 아니고 인터넷에 있는 주소록
-
웹 서버 · t-box 앱요청을 받아 처리하는 우리 프로그램 · HTTPS로 암호화되어 오갑니다
-
데이터베이스파일 정보 · 사용자 · 감사 로그를 저장 · 만들고·읽고·고치고·지움(CRUD)
-
파일 저장소실제 업로드된 파일을 보관
충님의 설명 ›
주소창에 도메인을 입력해도, 요청이 곧바로 우리 앱에 닿는 건 아닙니다. 먼저 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·파일 저장소).
터미널에 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를 껐다 켰다 해야 해서 번거롭거든요.
SSH로 접속했다면 창을 하나 더 열어 같은 VM에 한 번 더 접속하면 됨. 아래 ①②는 터미널 B, ③은 터미널 A에서 실행함.
curl -fsSL https://claude.ai/install.sh | bashsudo mkdir -p /var/www/html
sudo chown -R $USER /var/www/htmlcd /var/www/html
claudeclaude 처음 실행하면 로그인 안내가 나옴. 로그인한 뒤(또는 /login) 프롬프트 창에 한글로 요청 입력하면 됨. 터미널 B도 cd /var/www/html 해두면 편함.
- sudo
- “관리자 권한으로 실행”이란 뜻임. 시스템 폴더 만들거나 프로그램 설치할 땐 권한이 필요해서 명령 앞에 붙임. 비번 물으면 충님이 알려준 거 입력해 — 아래 ④에서 안 묻게 설정함.
- sudo chown -R $USER /var/www/html
/var/www/html폴더와 그 안의 모든 것(-R)의 소유자를 지금 나($USER)로 바꿉니다. 이래야 앞으로sudo없이도 그 폴더에서 자유롭게 파일을 만들고 지울 수 있어요.
첫 바이브 코딩 연습임. 터미널 A(Claude Code)에 아래 프롬프트 붙여넣어 명령어를 받고, 그걸 터미널 B에 붙여넣어 직접 실행함.
지금 이 리눅스 계정이 sudo를 쓸 때 비밀번호를 묻지 않도록 설정하고 싶어.
교육용 실습 VM이고, 내가 관리자 권한을 가지고 있어.
- visudo로 문법 검사를 하면서 /etc/sudoers.d/ 아래에 파일을 만드는 방식으로 알려줘
- 내 계정 이름은 직접 확인해서 넣어줘 (whoami)
- 실행할 명령어를 복사해서 쓸 수 있게 알려주고, 설정이 잘 됐는지 확인하는 방법도 알려줘
명령은 네가 실행하지 말고, 내가 터미널에 붙여넣어 직접 실행할게.
왜 “직접” 실행하냐? sudo 권한 설정은 시스템에서 가장 조심해야 할 작업 중 하나임. AI가 준 명령을 한 번 읽어보고 내 손으로 실행하는 습관이, 오늘 배울 “AI에게 맡기되 검증한다”의 첫 연습임.
받은 명령을 터미널 B에 붙여넣어 실행한 뒤 아래로 확인함. OK 나오면 성공.
sudo -n true && echo "OK" || echo "아직 비밀번호를 묻습니다"보안을 고려하지 않고 만든 t-box 실행
오늘은 먼저 부숴봄. 충님이 미리 만들어 둔 보안을 고려하지 않은 파일 공유 앱을 각자 VM에 올리고 내 도메인으로 접속되게 만듦. 이게 뒤 해킹 실습 대상임.
충님의 설명 ›
보통은 “만들고 → 고친다” 순서로 배우지만, 오늘은 반대로 갑니다. 먼저 보안을 고려하지 않은 서비스를 직접 공격해보고, “아, 이래서 위험하구나”를 몸으로 느낀 다음에 “그럼 제대로 만들려면?”을 이야기할 거예요.
이 앱은 순수 PHP + PostgreSQL로 만든 아주 작은 파일 공유 앱입니다. 로그인·권한·검증이 일부러 다 빠져 있어요. 저장소에 설치 안내서(INSTALL.md)가 들어 있어서, 코드를 내려받은 뒤 Claude Code에게 “INSTALL.md 읽고 설치해줘”라고만 하면 됩니다.
터미널 B에서 코드를 /var/www/html에 받음. (Claude Code 돌아가는 A는 그대로 둠.)
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가 옛 폴더를 봄.
저장소 안에 INSTALL.md라는 설치 안내서가 들어 있음. 명령어를 하나씩 칠 필요 없이, 터미널 A에 아래 한 줄만 붙여넣으면 Claude Code가 웹서버·DB·nginx 설정까지 알아서 해줌.
/var/www/html 의 INSTALL.md 를 읽고,
t-box가 내 VM에서 잘 실행되도록 설치해줘.
내 도메인은 "내이메일앞자리.tla.so" 야.
설치가 끝나면 브라우저로 접속되는지 확인하는 방법도 알려줘.
중간에 sudo 비번을 안 물어야 안 멈춤 — 그건 앞 단계(sudo 설정)에서 이미 처리했음.
내 도메인으로 접속하면 파일 목록(5개)이랑 업로드 폼 뜨냐? 위쪽 역할 전환 박스에서 Admin/Employee/Guest 바뀌냐?
해킹 타임 1 · 프론트 권한 우회 & XSS
공격 기술 학습이 아님. 잘못 만든 서비스가 왜 위험한지 직접 체감하는 시간임.
내 VM의 교육용 t-box에서만. 외부·회사 실제 시스템·타 참가자 VM 금지.
설치할 때 schema.sql이 예시 파일 5개를 이미 넣어놨음. 따로 업로드할 필요 없이 바로 시작하면 됨.
| 파일명 | 접근 레벨 |
|---|---|
| 회사소개.txt · 제품안내.txt | public |
| 사내공지.txt · 회의록.txt | internal |
| 급여명세_2026.txt | admin-only ← 뒤에서 “안 보여야 하는데 보이는” 주인공 |
목록이 비어 있으면 설치가 덜 된 거임 → INSTALL.md의 DB 단계를 다시 실행.
Employee에겐 삭제 버튼이 화면에서 숨겨져 있을 뿐, 버튼 자체는 브라우저 안에 그대로 있음. 숨긴 걸 다시 보이게 만들어 눌러봄.
| ID | 파일명 | 접근 레벨 | 동작 |
|---|---|---|---|
| 1 | 회사소개.txt | public | 받기 삭제 |
| 3 | 사내공지.txt | internal | 받기 삭제 |
| 5 | 급여명세_2026.txt | admin-only | 받기 삭제 |
- 1Admin이라 삭제 버튼 보이고 admin-only 파일(급여명세)도 목록에 있음. 정상임.
| ID | 파일명 | 접근 레벨 | 동작 |
|---|---|---|---|
| 1 | 회사소개.txt | public | 받기 — 삭제 버튼만 숨김 |
| 3 | 사내공지.txt | internal | 받기 — 삭제 버튼만 숨김 |
| 5 | 급여명세_2026.txt | admin-only | 받기 — 삭제 버튼만 숨김 |
- 2Employee인데 삭제 버튼만 사라졌을 뿐, 급여명세(admin-only)까지 그대로 보이고 “받기”도 눌립니다. 화면만 손봤을 뿐 서버는 아무도 안 막고 있어요. 여기서부터 실습 시작.
- Employee 계정으로 전환 → 목록에 삭제 버튼이 안 보이는 것 확인
- F12를 눌러 개발자도구 열기 → Elements(요소) 탭 선택
- 왼쪽 위 화살표 아이콘(Ctrl+Shift+C)을 켜고 파일 목록의 한 줄을 클릭 → 그 줄의 HTML로 이동
- 그 근처에서 삭제 버튼 태그를 찾습니다.
style="display:none"이나hidden,class="hidden"이 붙어 있을 거임 - 그 부분을 더블클릭해서 지우고 Enter → 화면에 삭제 버튼이 나타납니다
- 나타난 삭제 버튼을 클릭 → 파일이 진짜로 삭제되는지 확인
<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 쳐.
| 3 | 사내공지.txt | internal | 받기 삭제 |
// 삭제 버튼을 누르면 콘솔에 찍히는 서버 응답
{
"ok": true,
"deleted": "사내공지.txt",
"by": "employee01 (Employee)",
"note": "서버가 권한을 확인하지 않았습니다"
}
- 4Employee가 눌렀는데 서버가 그대로 삭제함. 서버는 “누가 보냈는지” 확인조차 안 함.
방금 무슨 일이 일어난 거임? 서버를 해킹한 게 아니라 내 브라우저 화면을 고쳤을 뿐임. 그런데 서버는 그 요청을 그대로 받아서 파일을 지움. 화면은 사용자 편의일 뿐 보안 장치가 아니라는 증거임.
버튼을 못 찾겠으면 콘솔에서 API를 직접 불러도 결과는 같음. 파일 ID(id=3)는 목록에 보이는 번호로 바꿔야 함 — Network 탭에서 실제 삭제 요청 주소 확인 가능함.
fetch("api/files.php?id=3", { method: "DELETE" })
.then((res) => res.json())
.then(console.log);콘솔에 코드를 처음 붙여넣으면 브라우저가 경고 띄우고 막음. “모르는 코드를 붙여넣게 해서 계정을 뺏는 사기”를 막으려는 장치임. 아래 순서로 한 번만 풀어.
- F12 → Console(콘솔) 탭으로 이동
- 붙여넣기를 시도하면 “이해하지 못했거나 직접 검토하지 않은 코드는 붙여넣지 마세요…” 경고가 뜹니다
- 콘솔에 아래 문구를 직접 타이핑하고 Enter
한글 브라우저붙여넣기 허용영문 브라우저allow pasting복사·붙여넣기 말고 손으로 쳐야 합니다. 둘 중 어느 걸 쓸지는 화면에 뜬 경고문 마지막 줄에 적혀 있어요. - 이제 위 코드를 붙여넣고 Enter → 파일이 삭제되는지 확인
이 경고가 왜 있는지 기억해 둬. 실제로 “이 코드를 콘솔에 붙여넣으면 이벤트 당첨”처럼 속여서 계정을 탈취하는 공격(셀프 XSS)이 흔함. 오늘처럼 내가 만든 실습 앱 아니면, 남이 준 코드를 콘솔에 붙여넣지 마.
Guest로 바꿔봄. 그래도 관리자 전용 급여명세_2026.txt가 목록에 보이고 “받기”를 누르면 실제로 내려받아짐. 화면에서 숨기지도 않은, 가장 노골적인 정보 유출임.
원인은 서버임. 개발자도구 Network 탭에서 api/files.php 응답을 열면 서버가 역할과 상관없이 모든 파일을 통째로 내려주는 게 보임.
- 위쪽 역할 전환을 Guest로 바꾸고 → 급여명세 파일이 보이는지 확인
- 그 줄의 “받기”를 눌러 실제로 내려받아지는지 확인
- F12 → Network 탭 → 새로고침 →
files.php응답에 admin-only가 있는지 확인
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로 내용까지 받아짐.
파일명이나 설명에 아래 값을 넣고 목록 화면으로 가면, 값이 글자가 아니라 코드로 실행됨.
<script>alert('나는 해커다!! 이 서비스는 해킹됐다!!')</script><img src=x onerror="alert('나는 해커다!! 이 서비스는 해킹됐다!!')">- 1설명은 그냥 글자일 뿐인데 서버가 검사 없이 저장하고 화면이 그대로 HTML로 출력함.
이 서비스는 해킹됐다!!
- 2내가 올린 파일을 다른 사람이 목록에서 보기만 해도 그 사람 브라우저에서 코드가 실행됨. 알림창 대신 쿠키를 훔쳐 보내는 코드였으면 계정 넘어감.
화면엔 삭제 버튼이 없었는데 왜 삭제됐을까요? 이 문제를 어디서 막아야 할까요?
→ 서버에서 사용자 역할을 확인 · DB의 접근 레벨과 역할을 비교 · 실패한 시도도 감사 로그에 남긴다.
해킹 타임 2 · SSRF와 방어 설계
t-box에 이미 들어있는 “URL로 파일 가져오기” 기능을 직접 공격해, 서버가 내부망 주소까지 접근해버리는 걸 확인함.
충님의 설명 ›
t-box에는 URL을 넣으면 서버가 그 주소로 접속하는 기능이 이미 들어 있습니다. 편리하지만, 사용자가 내부망 주소나 localhost를 넣으면 서버가 대신 접근할 수 있어 위험합니다. 이걸 SSRF라고 해요. 내 PC에서는 못 가는 주소도 서버 입장에서는 열리는 게 핵심입니다.
이 앱에는 검사 방식이 취약한 검사 / 방어된 검사 두 개 들어 있어요. 같은 주소를 두 방식으로 넣어보고 결과가 어떻게 갈리는지 직접 비교합니다.
t-box 아래쪽 “URL로 파일 가져오기” 칸에 아래 주소를 붙여넣고, 옆 검사 방식을 바꿔가며 검사를 눌러봄.
http://169.254.169.254/latest/meta-data- 위 주소를 붙여넣고 검사 방식 = 취약한 검사 → 검사 클릭 → 허용됨 ✅ 뜨는지 확인
- 같은 주소로 검사 방식 = 방어된 검사 → 검사 클릭 → 차단됨 ⛔ 뜨는지 확인
- 아래 표의 다른 주소들도 취약한 검사로 넣어보며 뭐가 통과되는지 확인
허용됨 ✅ http 문자열이 있으니 통과 (허술한 검사)
차단됨 ⛔ 내부 주소라서 차단 (169.254.169.254)
- !같은 주소인데 결과가 다릅니다. 취약한 검사는 “http가 들어 있으면 통과” 수준이라 내부망 주소를 그대로 통과시켜요. 이 주소는 클라우드 서버의 비밀 정보가 나오는 곳이라 실제 사고로 자주 이어집니다.
| 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 차단
- 리다이렉트 후 최종 주소 재검사
- 요청 시간 제한 · 응답 크기 제한
- 차단 이벤트를 감사 로그에 기록
왜 이렇게 쉽게 뚫렸을까 · 제대로 된 서비스란
방금 부순 걸 정리함. “그럼 제대로 만들려면 뭐가 달라야 하나”를 짚고, 다음 단계에서 설계로 옮김.
| 무엇이 뚫렸나 | 진짜 원인 | 제대로라면 |
|---|---|---|
| 권한 없이 파일 삭제 | 화면에서 버튼만 숨기고 서버는 검사 안 함 | 서버가 요청자의 역할을 확인 |
| 숨긴 파일이 다 보임 | 서버가 모든 파일을 내려주고 화면에서만 필터 | 권한 없는 데이터는 애초에 안 내려줌 |
| 파일명이 코드로 실행(XSS) | 입력값을 그대로 화면에 출력 | 출력할 때 글자로 안전하게 이스케이프 |
| 내부 주소 접근(SSRF) | 사용자가 준 URL을 검증 없이 서버가 요청 | http/https만·사설IP 차단·최종주소 재검사 |
| 누가 뭘 했는지 모름 | 기록(감사 로그)이 아예 없음 | 주요 행동·차단 이벤트를 로그로 남김 |
화면에서 버튼을 숨기는 것은 보안이 아니다. 서버가 권한을 확인해야 보안이다.
충님의 설명 ›
방금 우리가 한 공격은 대단한 기술이 아니었어요. 대부분 클릭 몇 번, 주소 하나였습니다. 그런데도 파일이 지워지고, 남의 자료가 보이고, 코드가 실행됐죠. 이게 보안을 나중으로 미룬 서비스의 실제 모습입니다.
공통점이 하나 있어요. “화면에서 막으면 되겠지”라고 생각한 겁니다. 하지만 화면은 사용자 손 안에 있어요. 진짜 방어선은 서버입니다. 그리고 방어는 기능을 만들 때 같이 넣어야지, 다 만든 뒤에 얹으려면 이미 늦습니다.
좋은 서비스는 “되게 만드는 것”에서 끝나지 않습니다. “나쁘게 쓰려는 사람”까지 생각하는 것입니다.
제대로 만들려면 · PRD와 아키텍처를 AI와 설계
방금 겪은 취약점이 처음부터 안 생기게, 무엇을 만들지(PRD)와 어떻게 만들지(아키텍처)를 AI와 상의해 문서로 남김. 이 문서가 숙제 출발점임.
충님의 설명 ›
많은 사람이 AI에게 바로 “앱 만들어줘”라고 합니다. 그러면 방금 본 것처럼 보안이 빠진 게 나올 수도 있어요. 그래서 만들기 전에 무엇을·어떻게 만들지 먼저 정리합니다 — 그게 PRD와 아키텍처예요.
핵심은 보안을 요구사항에 처음부터 적어 넣는 겁니다. “권한은 서버에서 확인”, “입력값은 안전하게 출력”, “주요 행동은 로그로” 같은 걸 PRD에 못 박아두면, AI도 그에 맞춰 만들어요.
좋은 바이브 코딩은 구현 요청 전에 설계 대화를 먼저 합니다. 그리고 그 결과를 문서로 남겨 계속 참조합니다.
회사 내부 파일 공유 서비스 t-box의 PRD를 만들어줘.
대상 사용자는 Admin, Manager, Employee, Guest야.
파일마다 접근 레벨(public, internal, team, admin-only)이 있어.
우리는 방금 "보안을 고려하지 않고 만든 버전"을 직접 공격해봤어. 그래서 이번엔
아래 보안 요구사항을 처음부터 PRD에 넣어줘:
- 권한 확인은 반드시 서버에서 한다
- 권한 없는 파일은 목록·다운로드 응답에 아예 포함하지 않는다
- 사용자 입력값(파일명·설명)은 화면에 안전하게 출력한다 (XSS 방어)
- URL 가져오기 기능이 있다면 내부 주소를 차단한다 (SSRF 방어)
- 업로드는 크기·형식을 제한한다
- 주요 행동과 차단 이벤트는 감사 로그로 남긴다
최소 기능부터 시작하고 보안·감사 로그·성능을 단계로 나눠서,
개발 초보자도 이해할 수 있게 써줘.
작성한 내용을 PRD.md 파일로 저장해줘.
t-box를 순수 PHP(프레임워크 없이), PostgreSQL, 파일 저장소로
만든다고 할 때 초보자용 아키텍처를 설명해줘.
내 서비스 도메인은 "내이메일앞자리.tla.so" 야.
특히 "권한 확인을 어디서 하는지", "파일 정보와 실제 파일을
어디에 저장하는지", "감사 로그를 어디에 남기는지"를
그림처럼 순서대로 설명해줘.
작성한 내용을 ARCHITECTURE.md 파일로 저장해줘.
지금 만든 PRD.md와 ARCHITECTURE.md를 보안 관점에서 검토해줘.
아까 우리가 뚫었던 4가지(프론트 권한 우회, 권한 없는 데이터 노출,
XSS, SSRF)가 이 설계대로 만들면 정말 막히는지 하나씩 확인해줘.
빠진 부분이 있으면 우선순위 순서로 알려줘.
숙제 · 제대로 된 t-box를 만들어 오기
오늘 만든 PRD.md·ARCHITECTURE.md를 근거로, 방금 뚫었던 취약점이 없는 파일 공유 서비스를 직접 완성해 옴. AI와 만들되 검증은 내가 함.
내가 만든 PRD.md와 ARCHITECTURE.md를 먼저 읽어줘.
그 문서에 맞춰서 t-box를 순수 PHP + PostgreSQL로 만들어줘.
이번엔 보안을 처음부터 넣어서 제대로 만들 거야:
- 권한 확인은 서버에서, 권한 없는 파일은 응답에 포함하지 않기
- 입력값은 출력할 때 안전하게 이스케이프
- 업로드 크기·형식 제한
- 주요 행동은 감사 로그로 기록
한 번에 다 만들지 말고, 기능 하나씩 만들고 내가 확인한 뒤
다음으로 넘어가자. 각 단계에서 커밋 메시지도 한글로 제안해줘.
다 만들었어. 이제 오늘 배운 공격을 내 앱에 똑같이 시도해줘:
1) Employee로 삭제 API 직접 호출 → 403으로 막히는지
2) 목록/다운로드 응답에 권한 없는 파일이 없는지
3) 파일명·설명 XSS가 글자로만 보이는지
4) 내부 주소 URL이 차단되는지
막히지 않는 게 있으면 어디를 고쳐야 하는지 알려줘.
완성한 코드를 Git 서버(git2.tla.so)의 내 저장소에 push하고, README에 “오늘의 4가지 공격이 어떻게 막히는지”를 짧게 적어 와. 그게 진짜 이해했다는 증거임. 저장소 만들기·토큰 발급·push 설정은 맨 아래 부록에 정리돼 있음.
마무리 · 오늘 잡은 감각
부수고 → 이해하고 → 설계까지 함. 남은 건 숙제로 완성하는 것. 오늘 핵심을 한 문장으로 정리함.
- 보안을 고려하지 않은 t-box를 직접 공격해 권한 우회·데이터 노출·XSS·SSRF를 겪음
- 그 원인이 서버·설계에 있었음을 이해
- 보안을 처음부터 넣은 PRD·아키텍처를 AI와 설계하고 문서로 저장
- 숙제 — 그 설계대로 제대로 된 t-box를 완성해 Git 서버에 push
가장 쉽게 뚫린 공격이 뭐였냐? 그 문제는 결국 어디서 막아야 하냐? AI한테 뭘 만들게 했고, 뭘 의심·검증하게 했냐?
부록 · Git 치트시트 & 문제 해결
막히면 여기. 숙제 제출용 Git 준비, 자주 쓰는 명령, 흔한 에러 해결법.
숙제(제대로 된 t-box)를 내 저장소에 올리려면 저장소와 토큰이 필요함.
- git2.tla.so에 로그인 → + → New Repository → 이름
t-box(README 체크 안 함, 빈 저장소) - 프로필 → 설정 → 어플리케이션 → 액세스 토큰 관리 → 새 토큰 → 권한에서 repository = 읽기와 쓰기 → 생성 후 토큰 복사
/var/www/html/.env에 계정·이메일·저장소주소·토큰을 넣고, Claude Code에 아래처럼 설정을 맡기기
/var/www/html/.env 에 GIT_USERNAME, GIT_EMAIL, GIT_REPOSITORY, GIT_TOKEN이 있어.
이 값으로 git을 초기화하고, 이름·이메일을 설정하고,
원격 저장소 origin을 토큰이 포함된 주소로 연결해줘.
.env는 .gitignore에 넣어 커밋되지 않게 해줘.
커밋 메시지는 항상 한글로 제안해줘.
⚠ 토큰은 .env에만. AI 대화창에 토큰 값을 직접 붙여넣지 마.
GIT 자주 쓰는 명령
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
계정·저장소 권한 확인, 토큰 재발급
지금 변경사항에 맞는 Git 커밋 메시지를 추천해줘.
한글로, 짧고 명확하게 3개 제안해줘.
나중에 봐도 무엇을 했는지 알 수 있는 문장으로.