"로그인된 채로 다른 사이트를 열기만 했을 뿐인데 자신도 모르게 송금이나 설정 변경이 일어난다" — 그것이 CSRF입니다. 작동 원리와 확실히 막는 법을 살펴봅니다(공격 절차는 다루지 않습니다).
왜 통하는가(메커니즘)
브라우저는 어떤 사이트에 대한 요청에 그 사이트의 쿠키를 자동으로 붙입니다. 그래서 사용자가 은행에 로그인되어 있다면, 악성 페이지에서 트리거된 은행으로의 요청에도 "사용자의 쿠키"가 그대로 실립니다. 서버 입장에서는 정당한 행동과 구분할 수 없습니다.
XSS가 "피해자의 브라우저에서 코드를 실행"하는 것이라면, CSRF는 "피해자의 로그인 상태를 빌리는" 것입니다(→ XSS란).
방어
CSRF 토큰 요구
상태를 바꾸는 행동(폼 제출, API)에는 서버가 발급한, 추측 불가능한 일회성 토큰을 요구하고 토큰이 없는 요청은 거부하세요. 대부분의 프레임워크가 이를 기본 제공합니다.
SameSite 쿠키 설정
세션 쿠키에 SameSite=Lax(또는 Strict)를 지정해, 크로스 사이트에서 시작된 요청에 쿠키가 붙지 않게 하세요. Lax는 현대의 기본값이며 그 자체로 큰 도움이 됩니다.
상태 변경에 GET을 쓰지 않기
GET(조회)은 부작용이 없어야 합니다. 변경은 POST/PUT/DELETE로 만들고 토큰 검증을 거치게 하세요.
Origin / Referer 검사
민감한 행동에 대해서는 요청의 Origin이 내 사이트인지 확인하고, 외부 오리진은 거부하세요.
본 사이트의 견해: 대체로 '해결됨'이지만 방심은 금물
프레임워크의 CSRF 토큰과 브라우저의 SameSite=Lax 기본값이 고전적 CSRF를 크게 줄였습니다. 그래도 커스텀 API, 레거시 구성, 토큰을 건너뛴 관리자 패널에서는 여전히 물립니다. "프레임워크에 맡긴다" 하더라도, 상태 변경 경로가 실제로 토큰 검증을 거치는지는 한 번 직접 확인하세요.
흔한 빈틈
메커니즘을 알더라도 구현은 두 곳에서 미끄러지기 쉽습니다.
- 부작용 있는 GET: 조회용 GET이 상태를 바꾸면, 이미지 태그나 평범한 링크 하나로도 CSRF가 됩니다. 상태 변경은 POST/PUT/DELETE로 만들고 토큰 검증을 거치게 하세요.
- 일부 경로의 토큰 검증 누락: 나중에 추가된 API와 관리자 기능은 종종 토큰을 건너뜁니다. "프레임워크에 있겠지"라고 가정하지 말고, 상태를 바꾸는 모든 경로를 한 번 정리해 점검하세요.
다음으로 읽기
FAQ
QCSRF는 XSS와 어떻게 다른가요?
XSS는 피해자의 브라우저에서 스크립트를 실행하고, CSRF는 피해자의 로그인 상태를 이용해 의도치 않은 요청을 보냅니다. CSRF는 스크립트를 전혀 실행하지 않아도 작동합니다 — 브라우저가 쿠키를 자동으로 보내는 것만으로 충분합니다.
QCSRF의 최우선 방어책은 무엇인가요?
상태를 바꾸는 요청(POST 등)에 CSRF 토큰을 요구하고, 세션 쿠키에 SameSite(Lax/Strict)를 설정하세요. 대부분의 프레임워크는 토큰을 기본 제공합니다. 그리고 상태 변경에는 절대 GET을 쓰지 마세요.
QSameSite만으로 충분한가요?
큰 도움이 되지만 만능은 아닙니다. 구형 브라우저, 일부 내비게이션, 특정 서브도메인 구성에는 빈틈이 남습니다 — 그러니 심층 방어를 위해 CSRF 토큰과 함께 쓰세요.