핵심 요약
CSRF(Cross-Site Request Forgery)는 로그인된 사용자의 브라우저가 자동으로 쿠키를 실어 보내는 점을 악용한다. 공격자 사이트가 몰래 은행 송금 요청을 날려도 브라우저가 세션 쿠키를 붙여 보내면 서버는 정상 요청으로 오인한다. 방어의 핵심은 "이 요청이 우리 사이트에서 나왔는가"를 검증하는 것이다.
1. 공격 원리
<!-- 공격자 페이지에 숨겨진 폼/이미지 -->
<img src="https://bank.com/transfer?to=attacker&amount=1000">
<!-- 피해자가 이 페이지를 열면 브라우저가
bank.com 세션 쿠키를 자동으로 붙여 요청 전송 -->
피해자는 은행에 로그인만 되어 있으면 클릭 없이도 당할 수 있다.
2. 방어 ① SameSite 쿠키 (기본 방어선)
| 값 | 동작 |
|---|---|
| Strict | 외부 사이트에서 온 요청엔 쿠키 안 보냄(가장 안전) |
| Lax | 기본값. GET 최상위 이동만 허용, POST 등은 차단 |
| None | 항상 전송(Secure 필수) — 크로스사이트 필요 시 |
Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax
3. 방어 ② CSRF 토큰
서버가 폼·세션에 예측 불가능한 토큰을 심고, 요청 시 함께 보내게 해 검증한다. 공격자는 이 토큰을 모르므로 위조 요청이 걸러진다. 쿠키가 아닌 헤더나 폼 필드로 보내는 게 포인트(쿠키로 보내면 자동 전송돼 의미 없음).
4. 방어 ③ 기타
- 변경 요청(POST·PUT·DELETE)은 GET으로 처리하지 않기 — 부수효과는 항상 POST 이상
- 중요한 작업엔 재인증·Origin/Referer 헤더 검증 추가
- 토큰 기반 인증(Authorization 헤더)은 쿠키 자동 전송이 없어 CSRF에 근본적으로 강함
5. XSS와 헷갈리지 말 것
CSRF는 "사용자를 속여 요청을 보내게" 하고, XSS는 "사이트에 악성 스크립트를 심는다". XSS가 뚫리면 CSRF 토큰도 훔쳐지므로 둘 다 막아야 한다.
자주 묻는 질문
SameSite=Lax만으로 충분한가요?
많은 CSRF를 막아주는 강력한 기본 방어선이지만 만능은 아닙니다. 일부 GET 기반 시나리오나 구형 브라우저를 고려해, 중요한 상태 변경엔 CSRF 토큰이나 토큰 기반 인증을 함께 쓰는 다중 방어를 권장합니다.
JWT를 헤더로 쓰면 CSRF는 신경 안 써도 되나요?
Authorization 헤더로 토큰을 보내면 브라우저가 자동 첨부하지 않으므로 전통적 CSRF에 강합니다. 단, 토큰을 쿠키에 저장하면 다시 CSRF 대상이 되고, localStorage에 두면 XSS 위험이 커집니다. 저장 위치 선택이 관건입니다.
CSRF 토큰은 어디에 저장하나요?
서버 세션(또는 서명된 쿠키)에 원본을 두고, 페이지 렌더 시 폼 필드나 meta 태그로 내려보내 요청 헤더에 실어 보냅니다. 서버는 세션의 값과 요청의 값을 비교합니다. 쿠키만으로 왕복시키면 자동 전송돼 방어 의미가 사라집니다.

댓글 0