HTTP Analyzer๋ ๋ธ๋ผ์ฐ์ /ํด๋ผ์ด์ธํธ์์ ๋ฐ์ํ HTTP ํธ๋ํฝ์ ์บก์ฒํ๊ณ , ์์ฒญ/์๋ต์ ๋์ผ๋ก ํ์ธํ๋ฉด์ ๋ณด์ ๊ด์ ์์ ๋น ๋ฅด๊ฒ ๋ถ๋ฅํ ์ ์๋๋ก ๋ง๋ ๋ก์ปฌ ๋ถ์ ๋๊ตฌ์
๋๋ค.
์ด ํ๋ก์ ํธ๋ ์ธ ๊ฐ์ง ์ถ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
mitmproxy๋ก ์ค์๊ฐ ํธ๋ํฝ์ ๊ฐ๋ก์ฑ๊ณ ์์ /๊ด์ฐฐNode + Express์๋ฒ๋ก ์บก์ฒ ์ํ, HAR ๋ถ์, ๋ฆฌํ๋ ์ด, Cloudflare R2 ํ์ผ ์ ์ฅ ์ฒ๋ฆฌReact + Viteํ๋ฐํธ์๋๋ก ์์ฒญ/์๋ต ํ์ธ, ๋ณด์ ํจํด ๋ถ์, ๋ฆฌํฌํธ ์ถ๋ ฅ
- ๊ตฌ๊ธ ๋ก๊ทธ์ธ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด
- ์ฌ์ด๋ ๋ฉ๋ด ๊ธฐ๋ฐ ๊ธฐ๋ฅ ๋ถ๋ฆฌ(
Overview,Capture,Findings,HAR,Recent Data) - ์ค์๊ฐ HTTP ์์ฒญ/์๋ต ์บก์ฒ
- Playwright ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ๊ฐ์ ๋๋ฉ์ธ ํฌ๋กค๋ง ์บก์ฒ
- ํฌ๋กค๋ง ์๋ฃ ๋๋ idle ์ํ ๊ฐ์ง ์ ์๋ ์บก์ฒ ์ค์ง
- SQLMap ๊ธฐ๋ฐ SQL Injection ํ๋ณด ์๋ํฌ์ธํธ ์ ๊ฒ ๋ฉ๋ด
- OpenAI API ๊ธฐ๋ฐ ํฌ๋กค๋ง ์๋ฃ Summary ์์ฑ
- ์์ฒญ/์๋ต ํค๋ ๋ฐ ๋ฐ๋ ํ์ธ
- ํน์ ์์ฒญ ์ฌ์ ์ก(Replay)
- ์บก์ฒ ํ๋ฆ ๊ธฐ๋ฐ Mermaid ๋ค์ด์ด๊ทธ๋จ ์์ฑ
- HAR ํ์ผ ์ ๋ก๋ ๋ฐ ์ฑ๋ฅ/ํธ์คํธ/์ํ์ฝ๋ ๋ถ์
- ๋ณด์ ํจํด ํ์ง ๋ฐ
OWASP Top 10๊ธฐ์ค ์์ฝ - ์๋ํฌ์ธํธ ์ฐ์ ์์ ์ ๋ฆฌ
Before / After๋น๊ต์ฉ DiffHTML / PDF / JSON / Markdown / CSV๋ฆฌํฌํธ ์ถ๋ ฅ- ์บก์ฒ ์ด๋ฒคํธ์ ์ ๊ฒ ์ด๋ ฅ์ Cloudflare R2 JSON ํ์ผ๋ก ์ ์ฅ
- ์ ๋ก๋๋ HAR ์๋ณธ ํ์ผ์ Cloudflare R2์ ์ ์ฅ
ํ๋ฐํธ์์ ์บก์ฒ๋ ์์ฒญ/์๋ต์ ๊ธฐ๋ฐ์ผ๋ก ์๋ ํญ๋ชฉ๋ค์ ํ์งํฉ๋๋ค.
- ๋ฏผ๊ฐ์ ๋ณด URL ๋ ธ์ถ
- ์๋ต ๋ณธ๋ฌธ ๋น๋ฐ๊ฐ ๋ ธ์ถ
- ์์ฒญ ๋ณธ๋ฌธ ๋ฏผ๊ฐ์ ๋ณด ํฌํจ
- ์ํํ CORS ์ค์
- ์ธ์
์ฟ ํค ์์ฑ ๋๋ฝ(
HttpOnly,Secure,SameSite) - ๋ณด์ ํค๋ ๋๋ฝ(
CSP,HSTS,X-Frame-Options,Referrer-Policy,X-Content-Type-Options) - ์๋ฒ ๋ฐฐ๋/๋ฒ์ ๋ ธ์ถ
- ์คํํธ๋ ์ด์ค/์์ธ ์ค๋ฅ ๋ ธ์ถ
- ๋๋ ํฐ๋ฆฌ ์ธ๋ฑ์ฑ ๋ ธ์ถ
- ์บ์ ์ ์ฑ ๋ถ์กฑ
- SQLi / XSS / SSRF / Path Traversal / Command Injection / Open Redirect ํ์
- Basic ์ธ์ฆ ์ฌ์ฉ ํ์
๊ฐ finding์ ๋ค์ ์ ๋ณด๋ฅผ ํจ๊ป ๋ณด์ฌ์ค๋๋ค.
- ์ฌ๊ฐ๋
- OWASP ๋ถ๋ฅ
- Evidence
- Guide
- Remediation
- Reproduction Checklist
- PoC Template
.
โโ proxy/
โ โโ modify_request.py
โ โโ requirements.txt
โ โโ rules.json
โโ server/
โ โโ index.js
โโ samples/
โ โโ sample.har
โ โโ sample-errors.har
โ โโ sample-security.har
โ โโ sample-large.har
โโ src/
โ โโ App.jsx
โ โโ main.jsx
โ โโ styles.css
โโ .env.example
โโ package.json
โโ README.md
์ฃผ์ ํ์ผ ์ค๋ช :
proxy/modify_request.pymitmproxy์ ๋์จ์ ๋๋ค.proxy/rules.json๊ท์น์ ์ฝ์ด์ ์์ฒญ ๋ฐ๋๋ฅผ ์์ ํ๊ณ ์๋ต์ ์ถ๋ ฅํฉ๋๋ค.server/index.jsํ๋ก ํธ API ์๋ฒ์ ๋๋ค. ์บก์ฒ ์ํ ์กฐํ, ๋ฆฌํ๋ ์ด, HAR ๋ถ์, ์บก์ฒ ์ด๋ฒคํธ ์ ์ฅ, ์ ๊ฒ ์ด๋ ฅ ์ ์ฅ์ ์ฒ๋ฆฌํฉ๋๋ค.src/App.jsx๋ฉ์ธ UI์ ๋๋ค. ๋ก๊ทธ์ธ, ์ฌ์ด๋ ๋ฉ๋ด, ์ค์๊ฐ ์์ฒญ ๋ชฉ๋ก, ๋ณด์ finding, ๋ฆฌํฌํธ ์ถ๋ ฅ, Diff, PoC ์ฃผ์ , ์ต๊ทผ ์ด๋ ฅ ํ๋ฉด ๋ฑ์ ๋ด๋นํฉ๋๋ค.samples/HAR ์ ๋ก๋ ํ ์คํธ์ฉ ์ํ ํ์ผ์ ๋๋ค.
- Node.js 18+
- npm
- Python 3.9+
mitmproxy- Cloudflare R2 ๋ฒํท
- Firebase ํ๋ก์ ํธ(Auth, ์ ํ์ HAR ๋ถ์ ์ด๋ ฅ)
- SQLMap(Optional, ๋ก์ปฌ Injection ์ ๊ฒ ์ ํ์)
npm install
pip install -r proxy/requirements.txtcp .env.example .env์์:
VITE_API_BASE_URL=https://http-analyzer-api.onrender.com
VITE_LOCAL_API_BASE_URL=http://127.0.0.1:5000
VITE_FIREBASE_API_KEY=<firebase-web-api-key>
VITE_FIREBASE_AUTH_DOMAIN=<project>.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=<project-id>
VITE_FIREBASE_STORAGE_BUCKET=<project>.firebasestorage.app
VITE_FIREBASE_MESSAGING_SENDER_ID=<messaging-sender-id>
VITE_FIREBASE_APP_ID=<firebase-app-id>
VITE_FIREBASE_MEASUREMENT_ID=<measurement-id>
PORT=4000
HOST=127.0.0.1
DISABLE_CAPTURE=false
DISABLE_SQLMAP=false
SQLMAP_BIN=sqlmap
OPENAI_API_KEY=<server-side-openai-api-key>
PLAYWRIGHT_HEADLESS=true
CAPTURE_READY_DELAY_MS=3000
CAPTURE_IDLE_AUTO_STOP_MS=10000
CAPTURE_CRAWL_ENABLED=true
CAPTURE_CRAWL_MAX_PAGES=8
CAPTURE_CRAWL_PAGE_DELAY_MS=1500
CAPTURE_LOGIN_WAIT_MS=3000
FIREBASE_SERVICE_ACCOUNT_JSON={"project_id":"<project-id>","client_email":"firebase-adminsdk@<project-id>.iam.gserviceaccount.com","private_key":"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"}
# ๋๋ ๊ฐ๋ณ ํ๊ฒฝ๋ณ์
FIREBASE_PROJECT_ID=<project-id>
FIREBASE_CLIENT_EMAIL=firebase-adminsdk@<project-id>.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n
# ๋๋ ๋ก์ปฌ ํ์ผ ๊ฒฝ๋ก
FIREBASE_SERVICE_ACCOUNT_PATH=/absolute/path/to/firebase-service-account.json
CLOUDFLARE_R2_ACCOUNT_ID=<cloudflare-account-id>
CLOUDFLARE_R2_ACCESS_KEY_ID=<r2-access-key-id>
CLOUDFLARE_R2_SECRET_ACCESS_KEY=<r2-secret-access-key>
CLOUDFLARE_R2_BUCKET=http-analyzer-files
CLOUDFLARE_R2_PUBLIC_BASE_URL=https://<public-bucket-host>
R2_HAR_ANALYSIS_INDEX_KEY=har/recent-index.json
R2_HAR_ANALYSIS_INDEX_LIMIT=50
R2_INSPECTION_INDEX_KEY=inspections/recent-index.json
R2_INSPECTION_INDEX_LIMIT=100๋ก์ปฌ์์ ํ๋ฐํธ์ ๋ฐฑ์๋๋ฅผ ๊ฐ์ด ์คํํ ๋๋ VITE_API_BASE_URL=http://127.0.0.1:5000์ผ๋ก ๋ฐ๊ฟ๋ ๋ฉ๋๋ค.
์ด์ ํ๋ฐํธ์์ ์์ฐฝ ์๋ ์บก์ฒ๋ฅผ ์ฌ์ฉํ ๋๋ ์ฌ์ฉ์ PC์ ๋ก์ปฌ ๋ฐฑ์๋๋ฅผ ํธ์ถํด์ผ ํ๋ฏ๋ก
VITE_LOCAL_API_BASE_URL=http://127.0.0.1:5000 ๊ฐ์ ์ ์งํฉ๋๋ค.
์ค๋ช :
VITE_*ํ๋ฐํธ์์ ์ฌ์ฉํ๋ ๊ฐ์ ๋๋ค.VITE_FIREBASE_*๋ Firebase Auth์ ์ฌ์ฉํฉ๋๋ค.FIREBASE_SERVICE_ACCOUNT_JSON๋๋FIREBASE_PROJECT_ID,FIREBASE_CLIENT_EMAIL,FIREBASE_PRIVATE_KEY,FIREBASE_SERVICE_ACCOUNT_PATH์๋ฒ์์ Firebase Admin์ ์ด๊ธฐํํ ๋๋ง ์ฌ์ฉํฉ๋๋ค. ์บก์ฒ/๋ถ์ ๊ฒฐ๊ณผ ์ ์ฅ์๋ ์ฌ์ฉํ์ง ์์ต๋๋ค.CLOUDFLARE_R2_*์บก์ฒ ์ด๋ฒคํธ, ์ ๊ฒ ์ด๋ ฅ, HAR ์๋ณธ ํ์ผ์ Cloudflare R2์ ์ ๋ก๋ํ ๋ ์ฌ์ฉํฉ๋๋ค.HOST๋ก์ปฌ์ ๋ณดํต127.0.0.1, Render ๊ฐ์ ๋ฐฐํฌ ํ๊ฒฝ์0.0.0.0์ ์ฌ์ฉํฉ๋๋ค.DISABLE_CAPTURE๋ฐฐํฌ ๋ฐฑ์๋์์ Playwright ์บก์ฒ API๋ฅผ ๋ง๊ณ ์ ์ฅ/์กฐํ API๋ง ์ด์ํ๋ ค๋ฉดtrue๋ก ๋ก๋๋ค.DISABLE_SQLMAPSQLMap ์คํ API๋ฅผ ๋ง์์ง ๊ฒฐ์ ํฉ๋๋ค. ๊ณต๊ฐ ๋ฐฐํฌ ํ๊ฒฝ์์๋ ์ ์ฉ ๋ฐฉ์ง๋ฅผ ์ํดtrue๋ฅผ ๊ถ์ฅํฉ๋๋ค.SQLMAP_BIN๋ก์ปฌ์ ์ค์น๋ SQLMap ์คํ ํ์ผ ๊ฒฝ๋ก์ ๋๋ค. ๊ธฐ๋ณธ๊ฐ์sqlmap์ ๋๋ค.CAPTURE_READY_DELAY_MS์ฒซ ํ์ด์ง ๋ก๋ ํ ์บก์ฒ ์ค๋น๋ฅผ ์ํด ๋๊ธฐํ๋ ์๊ฐ์ ๋๋ค. ๊ธฐ๋ณธ๊ฐ์3000์ ๋๋ค.CAPTURE_IDLE_AUTO_STOP_MS๋คํธ์ํฌ ํ๋์ด ์์ ๋ ์๋ ์ค์งํ๊ธฐ๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ์๊ฐ์ ๋๋ค. ๊ธฐ๋ณธ๊ฐ์10000์ ๋๋ค.CAPTURE_CRAWL_ENABLED,CAPTURE_CRAWL_MAX_PAGES,CAPTURE_CRAWL_PAGE_DELAY_MS์บก์ฒ ์์ ํ ๊ฐ์ ๋๋ฉ์ธ์ ๋งํฌ๋ฅผ ์๋ ์ํํ ์ง, ์ต๋ ๋ช ํ์ด์ง๊น์ง ๋ณผ์ง, ํ์ด์ง ์ฌ์ด์ ์ผ๋ง๋ ๊ธฐ๋ค๋ฆด์ง ์ค์ ํฉ๋๋ค.CAPTURE_LOGIN_WAIT_MSID/PW ์๋ ์ ๋ ฅ ํ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์๊ฐ์ ๋๋ค. ๊ธฐ๋ณธ๊ฐ์3000์ ๋๋ค.
mitmdump -s proxy/modify_request.pyํ๋ก์ ๊ธฐ๋ณธ ์ฃผ์:
- Host:
127.0.0.1 - Port:
8080
HTTPS๋ฅผ ๋ณด๋ ค๋ฉด mitmproxy ์ธ์ฆ์๋ฅผ ๋์ ํด๋ผ์ด์ธํธ/๋ธ๋ผ์ฐ์ ์ ์ค์นํด์ผ ํฉ๋๋ค.
npm run server๊ธฐ๋ณธ ์ฃผ์:
http://127.0.0.1:4000
npm run dev๊ธฐ๋ณธ ์ฃผ์:
http://localhost:5173
- ํ๋ฐํธ ์ ์ ํ ๊ตฌ๊ธ ๋ก๊ทธ์ธ ๋ฒํผ์ ๋๋ฆ ๋๋ค.
- ํ์ฌ ํ์ฉ๋ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธํด์ผ ๋ฉ์ธ ํ๋ฉด์ ๋ค์ด๊ฐ ์ ์์ต๋๋ค.
ํ์ฌ ํ์ฉ ๊ณ์ :
totoriverce@gmail.com
์ฐธ๊ณ :
- ๋ก๊ทธ์ธ ์ธ์ ์ Firebase Auth์ ๋ธ๋ผ์ฐ์ ์ง์์ฑ์ผ๋ก ์ ์ง๋ฉ๋๋ค.
- ์บก์ฒ/์ ๊ฒ ์ด๋ ฅ์ ๋จผ์ ๋ก์ปฌ ์ ์ฅ์์ ์ ์ฌ๋ ๋ค, ๋ฐฑ์๋ ๋๋ Firestore์ ๋๊ธฐํ๋ฉ๋๋ค.
Captureํ๋ฉด์์ ๋ถ์ ๋์ URL์ ์ ๋ ฅํฉ๋๋ค.- ํ์ํ๋ฉด ์ถ๊ฐ ์ ์ธ ํจํด์ ์ ๋ ฅํฉ๋๋ค.
- ๋ก๊ทธ์ธ ํ์ํ ์ฌ์ดํธ๋ผ๋ฉด
ID,PW๋ฅผ ์ ๋ ฅํ๊ฑฐ๋Session์ ์ฟ ํค ๊ฐ์ ์ ๋ ฅํฉ๋๋ค. ์บก์ฒ ์์์ ๋๋ฅด๋ฉด ์๋ฒ๊ฐ Playwright ๋ธ๋ผ์ฐ์ ๋ฅผ ์ด๊ณ ๋์ URL๋ก ์ด๋ํฉ๋๋ค.Session๊ฐ์ด ์์ผ๋ฉด ์ฟ ํค๋ก ๋จผ์ ์ ์ฉํ๊ณ , ์์ผ๋ฉด ID/PW๋ก ์ฒซ ํ๋ฉด์ ๋ก๊ทธ์ธ ํผ์ ์๋ ๊ฐ์งํด ์ ๋ ฅ/์ ์ถํฉ๋๋ค.- ์ฒซ ํ์ด์ง ๋ก๋ ํ 3์ด ๋๊ธฐํ ๋ค ๊ฐ์ ๋๋ฉ์ธ์ ๋งํฌ๋ฅผ ์ต๋
CAPTURE_CRAWL_MAX_PAGES๊ฐ๊น์ง ์๋ ์ํํฉ๋๋ค. - ํฌ๋กค๋ง์ด ์๋ฃ๋๋ฉด ์บก์ฒ๊ฐ ์๋ ์ค์ง๋๊ณ , ์ฌ์ด๋๋ฐ ์งํ ์ํ๊ฐ
complete๋ก ๋ฐ๋๋๋ค. - ์์ฒญ/์๋ต ๋ชฉ๋ก์ ๋ณด๋ฉด์ finding๊ณผ Diff๋ฅผ ํ์ธํฉ๋๋ค.
์ฐธ๊ณ :
- ์ด๋ฏธ์ง ์์ฒญ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํญ์ ์ ์ธ๋ฉ๋๋ค.
Excluded์ ๋ ฅ์นธ์ ์ถ๊ฐ ์ ์ธ ๊ท์น๋ง ๋ฐ์ต๋๋ค.ID,PW,Session์ ์ธ์ฆ ์๋ํ์๋ง ์ฌ์ฉํ๋ฉฐ ์ฑ ์ ์ฅ์์๋ ์ ์ฅํ์ง ์์ต๋๋ค.Session์SESSIONID=...๋๋SESSIONID=...; other=...๊ฐ์ Cookie ๋ฌธ์์ด์ ๊ถ์ฅํฉ๋๋ค. ๊ฐ๋ง ๋ฃ์ผ๋ฉดsession=<๊ฐ>์ฟ ํค๋ก ์ ์ฉํฉ๋๋ค.Capture์ฌ์ด๋๋ฐ์๋ ์บก์ฒ๋ ์์ฒญ ์, ์ ์ฒด ์์ฒญ ์, ํฌ๋กค๋ง ํ์ด์ง ์, ์ค๋ฅ ์๊ฐ ํ์๋ฉ๋๋ค.- ์๋์ผ๋ก ์ค์งํ๊ณ ์ถ์ผ๋ฉด
์บก์ฒ ์ค์ง๋ฅผ ๋๋ฅด๋ฉด ๋ฉ๋๋ค. Captureํ๋ฉด์์๋ ์์ฒญ๋ณ ๋ณด์ finding ์์ฝ๋ง ๋ณด์ฌ์ฃผ๊ณ , ์์ธ ๋ด์ฉ์Findings๋ฉ๋ด์์ ํ์ธํฉ๋๋ค.Findings์์ ๋ณด๊ธฐ๋ฅผ ๋๋ฅด๋ฉด ํด๋น ์์ฒญ์ finding๋ง ํํฐ๋์ด ๋ฐ๋ก ์ด๋ํฉ๋๋ค.- ์ข
๋ฃ ๊ณผ์ ์์ ๋ฐ์ํ
net::ERR_ABORTED๋ ์ข ๋ฃ์ฑ ๋ ธ์ด์ฆ๋ก ๊ฐ์ฃผํด UI์ Recent Data์์ ์จ๊น๋๋ค.
- ์์ฒญ ์นด๋๋ฅผ ํด๋ฆญํฉ๋๋ค.
- Replay ๋ชจ๋ฌ์์ URL, ํค๋, ๋ฐ๋๋ฅผ ์์ ํฉ๋๋ค.
์์ฒญ๋ฒํผ์ผ๋ก ๋ค์ ๋ณด๋ ๋๋ค.
๋ณด์ finding์ด ์๋ ๊ฒฝ์ฐ:
PoC๋ฅผ Replay์ ์ฃผ์๋ฒํผ์ผ๋ก ์ฌํ ํ ํ๋ฆฟ์ ๋ฐ๋ก ๋ชจ๋ฌ์ ๋ฃ์ ์ ์์ต๋๋ค.- ๊ธด ์๋ต์ ๋ชจ๋ฌ ๋ด๋ถ์์ ์คํฌ๋กค๋ฉ๋๋ค.
Capture ํ๋ฉด์ Generate Mermaid ๋ฒํผ์ผ๋ก ํ์ฌ ์บก์ฒ๋ ์์ฒญ์ ๊ธฐ๋ฐ์ผ๋ก Mermaid ํ๋ฆ๋๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
- ๊ฒฐ๊ณผ๋ ๋ณธ๋ฌธ์ด ์๋๋ผ ์ ์ฉ ํ์ ์ผ๋ก ํ์๋ฉ๋๋ค.
- ํ์
์ฐ์ธก ์๋จ
๋ณต์ฌ๋ฒํผ์ผ๋ก Mermaid ์ฝ๋๋ฅผ ๋ฐ๋ก ๋ณต์ฌํ ์ ์์ต๋๋ค. - ๋ณต์ฌ ํ ํ์ ์ ์๋์ผ๋ก ๋ซํ๋๋ค.
SQLMap ๋ฉ๋ด๋ ์บก์ฒ๋ ์์ฒญ ์ค SQL Injection ์ ๊ฒ ํ๋ณด๋ฅผ ๊ณจ๋ผ sqlmap์ผ๋ก ์คํํ ์ ์๋ ๋ก์ปฌ ์ ๊ฒ ๋๊ตฌ์
๋๋ค.
์ฌ์ฉ ํ๋ฆ:
Capture๋๋Recent Data์์ ์์ฒญ์ ํ๋ณดํฉ๋๋ค.SQLMap๋ฉ๋ด๋ก ์ด๋ํฉ๋๋ค.Captured Candidates์์ ์์ฒญ์ ์ ํํ๋ฉด URL, Method, Headers, Body๊ฐ ์๋ ์ ๋ ฅ๋ฉ๋๋ค.- ํ์ํ๋ฉด
Level,Risk, Header, Body ๊ฐ์ ์กฐ์ ํฉ๋๋ค. SQLMap Scan์ ๋๋ฌ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํฉ๋๋ค.
์ฃผ์:
- ๋ฐ๋์ ๋ณธ์ธ ์์ ๋๋ ๋ช ์์ ์ผ๋ก ํ๊ฐ๋ฐ์ ๋์์๋ง ์ฌ์ฉํด์ผ ํฉ๋๋ค.
- ๋ก์ปฌ ์๋ฒ์์
sqlmap๋ฐ์ด๋๋ฆฌ๋ฅผ ์คํํ๋ฏ๋ก ๋ก์ปฌ์ SQLMap์ด ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค. - macOS Homebrew ๊ธฐ์ค ์ค์น ์์๋
brew install sqlmap์ ๋๋ค. - ๊ณต๊ฐ Render ๋ฐฑ์๋์์๋
DISABLE_SQLMAP=true๋ก ์ฐจ๋จํฉ๋๋ค. - ๋ฐฐํฌ ํ๊ฒฝ์์ SQLMap์ ์ด์ด๋๋ฉด ์์ ์ธ๋ถ ๋์ ์ค์บ์ ์ ์ฉ๋ ์ ์์ผ๋ฏ๋ก ๊ถ์ฅํ์ง ์์ต๋๋ค.
Settings ๋ฉ๋ด์์ ํฌ๋กค๋ง ์๋ฃ ํ ์๋ ์์ฑํ Summary ์ค์ ์ ๊ด๋ฆฌํฉ๋๋ค.
์๋ฒ ํ๊ฒฝ๋ณ์ OPENAI_API_KEY๋ฅผ ์ค์ ํ๋ฉด ๋ธ๋ผ์ฐ์ ์ ํค๋ฅผ ์
๋ ฅํ์ง ์์๋ ์๋ฒ ํค๋ก Summary๋ฅผ ์์ฑํฉ๋๋ค.
์ ๋ ฅ ํญ๋ชฉ:
OPENAI KEY: ์ ํ ์ ๋ ฅ์ ๋๋ค. ์๋ฒOPENAI_API_KEY๊ฐ ์์ ๋๋ง ๋ธ๋ผ์ฐ์ localStorage ํค๋ก Summary๋ฅผ ์์ฑํฉ๋๋ค.MODEL: Summary ์์ฑ์ ์ฌ์ฉํ ๋ชจ๋ธ๋ช ์ ๋๋ค. ๊ธฐ๋ณธ๊ฐ์gpt-4.1-mini์ ๋๋ค.PROMPT: HTTP ์บก์ฒ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ค ๊ด์ ์ผ๋ก ์์ฝํ ์ง ์ ํ๋ ํ๋กฌํํธ์ ๋๋ค.
๊ธฐ๋ณธ ํ๋กฌํํธ๋ ๋ค์ ๊ด์ ์ ํฌํจํฉ๋๋ค.
- ์ ์ฒด ์์ฝ
- ์ํ๋ ์ฐ์ ์๋ํฌ์ธํธ
- SQL Injection, XSS, ์ธ์ฆ/์ธ์ , CORS, ๋ฏผ๊ฐ์ ๋ณด ๋ ธ์ถ ๊ทผ๊ฑฐ
- ์บก์ฒ ๋ฐ์ดํฐ ๊ธฐ๋ฐ ์ฆ๊ฑฐ์ ์ถ๊ฐ ํ์ธ ํ์ ํญ๋ชฉ ๋ถ๋ฆฌ
- SQLMap ์ ๊ฒ ํ๋ณด URL/ํ๋ผ๋ฏธํฐ ์ ์
- ๊ฐ๋ฐ์ ๋ค์ ์กฐ์น ์ฒดํฌ๋ฆฌ์คํธ
ํฌ๋กค๋ง์ด crawl-complete๋ก ์๋ ์ค์ง๋๋ฉด, API Key๊ฐ ์
๋ ฅ๋ ๊ฒฝ์ฐ ํ์ฌ ์บก์ฒ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Summary๊ฐ ์์ฑ๋ฉ๋๋ค. ์๋์ผ๋ก๋ ํ์ฌ ๋ฐ์ดํฐ๋ก Summary ์์ฑ ๋ฒํผ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
HAR ํ๋ฉด์์ ํ์ผ์ ์ ํํด ์
๋ก๋ํ ์ ์์ต๋๋ค. ์๋ฒ๋ ์๋ ํญ๋ชฉ์ ๊ณ์ฐํฉ๋๋ค.
- ์ด ์์ฒญ ์
- ํ๊ท ๋๊ธฐ ์๊ฐ
- ๊ฐ์ฅ ๋๋ฆฐ ์์ฒญ
- ๋ฉ์๋ ๋ถํฌ
- ์์ ํธ์คํธ
- ์ํ์ฝ๋ ๋ถํฌ
- ์ฝํ ์ธ ํ์ ๋ถํฌ
- ์คํจ ์์ฒญ ๋ชฉ๋ก
๋ถ์ ์์ฒด๋ Firebase ์์ด๋ ๊ฐ๋ฅํ์ง๋ง, ๊ฒฐ๊ณผ ํ์ผ์ ์๋ฒ์ ์ ์ฅํ๋ ค๋ฉด Cloudflare R2 ์ค์ ์ด ํ์ํฉ๋๋ค.
Recent Data ํ๋ฉด์์๋ ์๋ ๋ด์ฉ์ ํ์ธํ ์ ์์ต๋๋ค.
- ์ต๊ทผ ์ ๊ฒ ์ด๋ ฅ
- ์ต๊ทผ ์บก์ฒ ์ด๋ฒคํธ
- ์ต๊ทผ 7์ผ / 30์ผ ๊ธฐ์ค ํต๊ณ ๋์๋ณด๋
- ์ ๊ฒ ์ด๋ ฅ ์์ธ ๋ชจ๋ฌ
- ์ ๊ฒ ์ด๋ ฅ๋ณ
HTML / PDF๋ฆฌํฌํธ ์ฌ๋ค์ด๋ก๋ - ํญ๋ชฉ๋ณ ์ ์ฅ ์ถ์ฒ(
Cloudflare R2)
์ค์:
- ์บก์ฒ ๊ฒฐ๊ณผ๋ Cloudflare R2 ํ์ผ ์ ์ฅ์ด ์ฑ๊ณตํด์ผ
Recent Data์ ํ์๋ฉ๋๋ค. - ํ์ผ ์ ์ฅ์ด ์คํจํ๋ฉด ๋ก์ปฌ ๋๊ธฐ ํญ๋ชฉ์ผ๋ก ํ์ํ์ง ์๊ณ ์ ์ฅ ์คํจ ๋ฉ์์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
Recent Data๋ R2์inspections/recent-index.json์ธ๋ฑ์ค๋ฅผ ๊ธฐ์ค์ผ๋ก ํ์ํฉ๋๋ค.
- ํ์ฌ ์บก์ฒ/๋ถ์ ๊ฒฐ๊ณผ ์ ์ฅ์๋ Firestore ์ปฌ๋ ์ ์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
- Firebase๋ ์ธ์ฆ๊ณผ ๊ธฐ์กด ํ๋ก์ ํธ ํธํ ๋ชฉ์ ์ผ๋ก๋ง ๋จ์ ์์ต๋๋ค.
- ์บก์ฒ ์ด๋ฒคํธ:
inspections/events/YYYY-MM-DD/<session-id>.json - ์ ๊ฒ ์ด๋ ฅ / ๋ฆฌํฌํธ ์ค๋
์ท:
inspections/runs/YYYY-MM-DD/<run-id>.json - Recent Data ์ธ๋ฑ์ค:
inspections/recent-index.json - HAR ๋ถ์ ๊ฒฐ๊ณผ:
har/analyses/YYYY-MM-DD/<analysis-id>.json - HAR ๋ถ์ ์ธ๋ฑ์ค:
har/recent-index.json - HAR ์๋ณธ ํ์ผ๊ณผ ์์ฑ ๋ฆฌํฌํธ ์ฒจ๋ถ ํ์ผ๋ Cloudflare R2์ ์ ์ฅํฉ๋๋ค.
์ฃผ์:
FIREBASE_SERVICE_ACCOUNT_JSON๊ณผCLOUDFLARE_R2_SECRET_ACCESS_KEY๋ ์๋ฒ ์ ์ฉ์ ๋๋ค.- ํ๋ฐํธ ์ฝ๋์ ์ง์ ๋ ธ์ถํ๋ฉด ์ ๋ฉ๋๋ค.
์ด ์ ์ฅ์๋ ํ๋ฐํธ์ ๋ฐฑ์๋๋ฅผ ๋ถ๋ฆฌํด์ ๋ฐฐํฌํ๋๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
- ํ๋ฐํธ: GitHub Pages
- ๋ฐฑ์๋: Render Web Service
- DB: Firebase Firestore
- File Storage: Cloudflare R2
GitHub ์ ์ฅ์ Settings > Secrets and variables > Actions์ ์๋ ๊ฐ์ ๋ฑ๋กํฉ๋๋ค.
ํ๋ฐํธ API URL์ ์ ์ฅ์ ๋ณ์(Variables)๋ก ๋ฑ๋กํฉ๋๋ค. ๊ฐ์ ๋ฑ๋กํ์ง ์์ผ๋ฉด GitHub Actions๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก https://http-analyzer-api.onrender.com์ ์ฌ์ฉํฉ๋๋ค.
VITE_API_BASE_URL=https://http-analyzer-api.onrender.com
VITE_LOCAL_API_BASE_URL=http://127.0.0.1:5000
Render ์๋ ๋ฐฐํฌ ํธ๋ฆฌ๊ฑฐ์ฉ:
RENDER_DEPLOY_HOOK_URL=<render-deploy-hook-url>
RENDER_DEPLOY_HOOK_URL์ Render ์๋น์ค์ Settings > Deploy Hook์์ ์์ฑํ URL์
๋๋ค. ์ด ๊ฐ์ด ์์ผ๋ฉด ํ๋ฐํธ ๋ฐฐํฌ๋ง ์งํ๋๊ณ ๋ฐฑ์๋ ๋ฐฐํฌ ํธ๋ฆฌ๊ฑฐ ๋จ๊ณ๋ ๊ฑด๋๋๋๋ค.
Render Web Service์๋ ์๋ ๊ฐ์ ๋ฑ๋กํฉ๋๋ค.
NODE_ENV=production
HOST=0.0.0.0
DISABLE_CAPTURE=false
PLAYWRIGHT_HEADLESS=true
DISABLE_SQLMAP=true
FIREBASE_PROJECT_ID=<project-id>
FIREBASE_CLIENT_EMAIL=<firebase-client-email>
FIREBASE_PRIVATE_KEY=<firebase-private-key>
CLOUDFLARE_R2_ACCOUNT_ID=<cloudflare-account-id>
CLOUDFLARE_R2_ACCESS_KEY_ID=<r2-access-key-id>
CLOUDFLARE_R2_SECRET_ACCESS_KEY=<r2-secret-access-key>
CLOUDFLARE_R2_BUCKET=<r2-bucket-name>
CLOUDFLARE_R2_PUBLIC_BASE_URL=<public-bucket-host>
R2_HAR_ANALYSIS_INDEX_KEY=har/recent-index.json
R2_HAR_ANALYSIS_INDEX_LIMIT=50
R2_INSPECTION_INDEX_KEY=inspections/recent-index.json
R2_INSPECTION_INDEX_LIMIT=100
๋ฐฐํฌ ๋ฐฑ์๋์์๋ ์บก์ฒ API๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก DISABLE_CAPTURE=false๋ก ๋ก๋๋ค.
- ๋์:
/api/health,/api/capture/start,/api/capture/status,/api/capture/stop,/api/replay-request,/api/recent-analyses,/api/inspection-runs,/api/capture-events/batch,/api/analyze-har - Render์์๋
PLAYWRIGHT_HEADLESS=true๋ก ์๋ฒ ๋ด๋ถ headless Chromium์ ์คํํฉ๋๋ค. - Render์์๋ SQLMap API๋ฅผ ๊ธฐ๋ณธ ์ฐจ๋จํฉ๋๋ค.
render.yaml์DISABLE_SQLMAP=true๋ ์๋๋ ๋ณด์ ์ค์ ์ ๋๋ค.
์ฃผ์: Render์์ ์คํ๋๋ ๋ธ๋ผ์ฐ์ ๋ ์ฌ์ฉ์ PC๊ฐ ์๋๋ผ Render ์๋ฒ ๋ด๋ถ ๋ธ๋ผ์ฐ์ ์ ๋๋ค. ์ฌ๋์ด ์ง์ ๋ก๊ทธ์ธํ๊ณ ์กฐ์ํ๋ ์ธ์ ์บก์ฒ๋ ๋ก์ปฌ ์ฑ์์ ์คํํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ ํํฉ๋๋ค.
render.yaml์ด ํฌํจ๋์ด ์์ผ๋ฏ๋ก Render์์ Blueprint๋ก ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.
- Service Name:
http-analyzer-api - Build Command:
npm ci - Start Command:
npm run start - Health Check Path:
/api/health - ์์ ๋ฐฑ์๋ URL:
https://http-analyzer-api.onrender.com
Render์์ ์๋น์ค ์ด๋ฆ์ด ์ด๋ฏธ ์ฌ์ฉ ์ค์ด๋ฉด ์ค์ ์์ฑ๋ URL์ GitHub Actions ๋ณ์ VITE_API_BASE_URL์ ๋ค์ ๋ฑ๋กํด์ผ ํฉ๋๋ค.
๋ฐฐํฌ ์ฌ์ดํธ์์๋ ๊ธฐ์กด ๋ฉ๋ด๋ ๊ทธ๋๋ก ํ์๋ฉ๋๋ค.
Overview,Capture,Findings,HAR,Recent Data๋ฉ๋ด ํ์HAR์ ๋ก๋,Replay, ๋ฆฌํฌํธ ์ถ๋ ฅ์ ๋ฐฑ์๋ API URL์ ํตํด ์คํ- Render ํ๊ฒฝ์์๋ headless Chromium์ผ๋ก ์บก์ฒ๊ฐ ์คํ๋จ
- ์ค์ ๋ธ๋ผ์ฐ์ ์ฐฝ์ ๋์ ์ธ์ ์ ์ด์ด๊ฐ๋ ์บก์ฒ๋ ๋ก์ปฌ ์ฑ์์ ์คํํ๋ ๊ฒ์ ๊ถ์ฅ
์ด ์ ์ฅ์๋ ์๋ฒ์์ ๋ค์ Cloudflare R2 ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ๋๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
har/analyses/YYYY-MM-DD/...๊ฒฝ๋ก์ HAR ๋ถ์ ๊ฒฐ๊ณผ ์ ์ฅhar/recent-index.json๊ฒฝ๋ก์ HAR ์ต๊ทผ ์ด๋ ฅ ์ธ๋ฑ์ค ์ ์ฅinspections/events/YYYY-MM-DD/...๊ฒฝ๋ก์ ์บก์ฒ ์ด๋ฒคํธ ์ ์ฅinspections/runs/YYYY-MM-DD/...๊ฒฝ๋ก์ ์ ๊ฒ ์ด๋ ฅ๊ณผ ๋ฆฌํฌํธ ์ค๋ ์ท ์ ์ฅinspections/recent-index.json๊ฒฝ๋ก์ Recent Data ์ธ๋ฑ์ค ์ ์ฅ
์๋จ Export ๋ฉ๋ด์์ ๋ค์ ํฌ๋งท์ ์ถ๋ ฅํ ์ ์์ต๋๋ค.
- HTML
- JSON
- Markdown
- CSV
๋ฆฌํฌํธ์๋ ๋ค์ ์ ๋ณด๊ฐ ํฌํจ๋ฉ๋๋ค.
- ํ์ง
- ์ ๊ฒ์
- ์ ๊ฒ ์ผ์
- ๊ฒฐ๋ก
- ์์ฒญ/์๋ต ๋ชฉ๋ก
- ๋ณด์ finding
- OWASP ์์ฝ
- ์๋ํฌ์ธํธ ์ํ๋ ์์ฝ
Mask Secrets๊ฐ ์ผ์ ธ ์์ผ๋ฉด ๋ฏผ๊ฐ์ ๋ณด๋ ๋ง์คํน๋ ์ํ๋ก ์ถ๋ ฅ๋ฉ๋๋ค.
ํ ์คํธ์ฉ HAR ํ์ผ์ samples์ ๋ค์ด ์์ต๋๋ค.
- samples/sample.har ๊ธฐ๋ณธ ์ ๋ก๋/์ ์ฅ ๋์ ํ์ธ์ฉ
- samples/sample-errors.har ์ค๋ฅ ์๋ต๊ณผ ์คํจ ์์ฒญ ํ์ธ์ฉ
- samples/sample-security.har ๋ณด์ ํจํด ํ์ง ํ์ธ์ฉ
- samples/sample-large.har ๋๋ ์์ฒญ ํ๋ฆ ํ์ธ์ฉ
- samples/sample-vulnerable.har ๋ฏผ๊ฐ์ ๋ณด ๋ ธ์ถ, ๋ณด์ ํค๋ ๋๋ฝ, ์ฃผ์ ํ์ ๋ฑ ์ทจ์ฝ ์งํ ํ ์คํธ์ฉ
๋ฏผ๊ฐ๊ฐ์ ๊ธฐ๋ณธ ๋ง์คํนํฉ๋๋ค.
์:
AuthorizationCookieSet-Cookie- ํ ํฐ/JWT/API Key
- Private Key ํ์ ๋ฌธ์์ด
finding๋ง๋ค ๋ค์ ๋ฒ์๋ก ์ต์ ํ ์ ์์ต๋๋ค.
- ์ธ์ ์คํ
- ์๋ํฌ์ธํธ ์คํ
- ํธ์คํธ ์คํ
- ์ ์ญ ์คํ
๊ฐ์ ์๋ํฌ์ธํธ์ ์ด์ ์์ฒญ๊ณผ ํ์ฌ ์์ฒญ์ ๋น๊ตํฉ๋๋ค.
- ์ํ์ฝ๋
- ๋ฐ๋ ์์ฒญ ํค๋
- ๋ฐ๋ ์๋ต ํค๋
- ์์ฒญ ๋ฐ๋
- ์๋ต ๋ฐ๋
๊ธฐ๋ณธ ์ํ๋ ์ ํ์ ๋๋ค.
finding์ด ๋ง์ด ๋ชฐ๋ฆฐ ์๋ํฌ์ธํธ๋ฅผ ์ฐ์ ์์๋ก ์ ๋ฆฌํฉ๋๋ค.
- ๋์ ์ ์
- finding ๊ฐ์
- ์ต๊ณ ์ฌ๊ฐ๋
- ์์ฃผ ๊ฑธ๋ฆฐ OWASP ์นดํ ๊ณ ๋ฆฌ
๊ธฐ๋ณธ ์ํ๋ ์ ํ์ ๋๋ค.
์ต๊ทผ ์ ๊ฒ ์ด๋ ฅ๊ณผ ์บก์ฒ ์ด๋ฒคํธ๋ Cloudflare R2 ํ์ผ ์ ์ฅ ์ฑ๊ณต ๊ธฐ์ค์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.
- ์บก์ฒ ์ด๋ฒคํธ: R2 JSON ํ์ผ๋ก ์ ์ฅ
- ์ ๊ฒ ์ด๋ ฅ: R2 JSON ํ์ผ๋ก ์ ์ฅ
- HAR ๋ถ์ ๊ฒฐ๊ณผ: R2 JSON ํ์ผ๋ก ์ ์ฅ
- Recent Data: R2 ์ธ๋ฑ์ค ํ์ผ์์ ์ต๊ทผ ์ ๊ฒ ์ด๋ ฅ๋ง ์กฐํ
ํ์ผ ์ ์ฅ์ด ์คํจํ๋ฉด Recent Data์ ๋ก์ปฌ ๋๊ธฐ ํญ๋ชฉ์ ๋ง๋ค์ง ์๊ณ ์ ์ฅ ์คํจ ๋ฉ์์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
npm run buildnpm run servernpm run dev- ์ด ๋๊ตฌ์ finding์ ํ์ ์ทจ์ฝ์ ์ด ์๋๋ผ ํจํด ๊ธฐ๋ฐ ํ์ง์ ๋๋ค.
- ์ค์ ์ทจ์ฝ ์ฌ๋ถ๋ ์ฌํ ํ ์คํธ์ ์๋ฒ ์ฝ๋/์ธํ๋ผ ์ค์ ๊ฒํ ๋ก ํ์ธํด์ผ ํฉ๋๋ค.
- Firebase ์๋น์ค ๊ณ์ ํค์ Cloudflare R2 ๋น๋ฐํค๋ ์ ๋ ๋ธ๋ผ์ฐ์ ๋ ๊ณต๊ฐ ์ ์ฅ์์ ๋ ธ์ถํ๋ฉด ์ ๋ฉ๋๋ค.
- finding ๊ฒฐ๊ณผ์ ํ๋ก์ ํธ๋ณ ์ ์ฅ/์กฐํ ํ๋ฉด
- replay ๊ฒฐ๊ณผ ์๋ ๋น๊ต
- finding๋ณ ์ฝ๋ฉํธ ๋ฐ triage ์ํ
- ํ ๊ณต์ ์ฉ ๋ณด๊ณ ์ ํ ํ๋ฆฟ
- ํน์ finding ๋ฐ์ ์ Slack/์ด๋ฉ์ผ ์๋ฆผ