사용자가 은행에 로그인한 상태에서 이 악성 사이트를 방문하면…
브라우저에 저장된 세션 쿠키가 자동으로 함께 전송됩니다.
CSRF 방어 활성화 OFF
<!-- evil-site.com 에 숨겨진 폼 --><form action="http://bank.example.com/transfer"
method="POST" id="csrf"><input type="hidden" name="to"
value="해커계좌"/><input type="hidden" name="amount"
value="1000000"/></form><script>
document.getElementById("csrf").submit();
// 사용자 모르게 자동 제출!</script>
🐍 FastAPI 서버 코드 main.py
@app.post("/transfer")
async deftransfer(
request: Request,
to: str = Form(...),
amount: int = Form(...),
):
# ❌ 세션만 확인 — CSRF 토큰 없음!
session = request.cookies.get("session")
if not session:
raiseHTTPException(401)
# 세션만 있으면 바로 송금 처리 💀return {"status": "transferred",
"to": to,
"amount": amount}
@app.post("/transfer")
async deftransfer(
request: Request,
to: str = Form(...),
amount: int = Form(...),
csrf_token: str = Form(...), # ✅ 추가
):
session = request.cookies.get("session")
if not session:
raiseHTTPException(401)
# ✅ CSRF 토큰 검증
expected = session_store[session]["csrf_token"]
if csrf_token != expected:
raiseHTTPException(403,
detail="CSRF 토큰 불일치 — 요청 차단")
return {"status": "transferred",
"to": to,
"amount": amount}
📋 서버 요청 로그 실시간
// 서버 대기 중...
📊 피해 현황
정상 송금 횟수0
CSRF 공격 성공0
CSRF 공격 차단0
⚡ CSRF 공격 흐름
① 사용자 로그인
→
② 세션쿠키 발급
↓
③ 악성사이트 방문
→
④ 숨겨진 폼 자동제출
↓
⑤ 쿠키 자동 포함 전송
→
⑥ 서버: 정상 처리 💀
핵심 원인: 브라우저는 요청 출처(origin)에 상관없이
해당 도메인의 쿠키를 자동으로 함께 보냅니다.
서버는 쿠키만으로는 "누가 보낸 요청인지" 구별할 수 없습니다.
🛡️ FastAPI 방어 방법 3가지
① CSRF 토큰 로그인 시 서버가 난수 토큰 생성 → 폼에 hidden 필드로 포함 → 서버에서 검증.
악성 사이트는 토큰값을 알 수 없어서 위조 불가.
② SameSite 쿠키 세션 쿠키에SameSite=Strict또는Lax설정.
다른 도메인에서 출발한 요청에는 쿠키가 전송되지 않음.