27 CSRF
개요
Cross-Site Request Forgery
- 사용자가 인증된 상태에서 공격자가 의도한 요청을 강제로 실행시키는 공격
- “사용자가 자신도 모르게 공격자의 의도대로 서버에 요청을 보내게 만드는 것”
공격 시나리오
- 사용자가 bank.com에 로그인함 (세션 쿠키가 브라우저에 저장)
- 공격자가 만든 악성 웹사이트(
evil.com)에 사용자가 방문함bank.com에 접속하자마자evil.com에 사용자 자신도 모르게 방문하게 됩니다.
- 그 페이지에 다음과 같은 코드가 숨겨져 있음
<img src="https://bank.com/transfer?to=hacker&amount=1000000">
- 브라우저는
bank.com의 세션 쿠키를 자동으로 포함해 요청을 보냄 - 서버는 이 요청을 "정상적인 사용자 요청"으로 인식함
- 공격자 계좌로 송금 완료
원인
- 브라우저가 자동으로 쿠키나 인증 정보를 전송하기 때문입니다.
- 브라우저는 각각 웹 홈페이지의 쿠키/인증 정보를 가지고 있음
- 인터넷 도구 > application > cookies, local storage, session storage에 저장되는 값이 많습니다.
- 서버가 클라이언트의 요청이 진짜 사용자의 의도인지 확인하지 않기 때문입니다.
CSRF 방어
서버사이드에서 HTTP 헤더의 적절한 설정을 해주는 것으로 막을 수 있습니다.사용자 인증(Authentication) 이후 로그인 상태를 토큰에 담아 저장하는데, 이 토큰이 브라우저에 저장됩니다. CSRF는 로그인이 된 사용자의 브라우저에서 다른 사이트로 Cross-Site 원치 않는 요청을 보내는 공격으로 이해했습니다.
- CSRF Token 사용
- 각 요청에 고유한 난수 토큰을 포함 → 서버가 검증함
SameSiteCookie속성 설정- 쿠키를 외부 사이트 요청에 자동 전송하지 않게 설정
Referer/ Origin검증- 요청의 출처를 확인하여 다른 도메인 차단
- 사용자 재인증
- 민감한 요청(비밀번호 변경 등) 시 재로그인 요구
CSRF Token 예시
Csrf token
- 서버는 요청 수신 시 세션에 저장된 토큰과 요청에 포함된 토큰을 비교
- 일치하지 않으면 요청 거부 (
403 Forbidden) DVWA웹 사이트 로그인에도csrftoken이 적용되어있음
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="ABC123XYZ">
<input type="text" name="to">
<input type="number" name="amount">
<button>Send</button>
</form>
예시
HTTP 헤더에 설정할 수 있습니다.
SameSite=StrictHTTP헤더 보안 설정 예시:Set-Cookie: sessionid=abcd1234; SameSite=Strict;Secure; HttpOnlySameSite필드의 값 3가지입니다.- Strict → 외부 사이트 요청에는 쿠키 전송 안 함 (가장 안전)
- Lax → 일부 안전한 요청만 허용
- None → 제3자 요청에도 쿠키 전송 (HTTPS 필수)
HTTPOnly쿠키는 브라우저의 JS로 쿠키에 접근할 수 없게 만듭니다
CSRF vs XSS 비교
| 항목 | CSRF | XSS |
|---|---|---|
| 공격 대상 | 서버 | 사용자 |
| 공격 방식 | 인증된 사용자의 권한 악용 | 악성 스크립트를 주입 |
| 주요 원인 | 인증 검증 부족 | 입력 값 검증 부족 |
| 방어 기법 | CSRF Token, SameSite Cookie | 입력 필터링, CSP |
- 요새 웹-프레임워크가 잘되어 있어 기본적으로 개발 단에서 방어기능을 지원하는 경우가 많다고 합니다.
- Django –csrf_exempt
- 개발자 편의상 csrftoken을 제거하는 경우도 많아서 csrf공격이 유효할 수도 있다고 합니다.