CSRF(Cross-Site Request Forgery)란 무엇이며 방어 방법은 무엇인가요?
답변 포인트
인증 쿠키가 자동으로 전송되는 특성을 악용하는 공격입니다.
정답 및 해설
빠른 요약
CSRF는 사용자가 로그인한 사이트에 대해 공격자가 의도한 요청을 사용자의 브라우저가 대신 보내게 만드는 공격입니다. 인증 쿠키가 자동 전송되는 특성을 악용합니다.
CSRF는 사용자가 이미 로그인한 사이트에 대해, 공격자가 의도한 요청을 사용자의 브라우저가 대신 보내게 만드는 공격입니다. 사용자의 인증 쿠키가 자동으로 포함된다는 점을 악용합니다.
공격 시나리오
사용자가 은행 사이트에 로그인해 쿠키를 가진 상태라고 가정합니다.
<form action="https://bank.example.com/transfer" method="POST">
<input name="to" value="attacker" />
<input name="amount" value="100000" />
</form>
<script>
document.forms[0].submit();
</script>사용자가 공격 페이지에 접속하면 브라우저는 은행 사이트로 요청을 보내고, 은행 쿠키가 자동으로 함께 전송될 수 있습니다.
CSRF가 성립하는 조건
- 인증 정보가 쿠키처럼 자동 전송됩니다.
- 서버가 요청의 출처나 의도를 검증하지 않습니다.
- 상태 변경 요청이 단순한 폼 제출 등으로 가능해야 합니다.
방어 방법 1: CSRF Token
서버가 예측 불가능한 토큰을 발급하고, 상태 변경 요청에 토큰을 함께 보내도록 합니다.
<input type="hidden" name="csrfToken" value="random-token" />서버는 세션에 저장된 토큰과 요청 토큰이 일치하는지 검증합니다. 공격자는 다른 사이트의 토큰 값을 읽을 수 없으므로 유효한 요청을 만들기 어렵습니다.
방어 방법 2: SameSite Cookie
SameSite는 cross-site 요청에서 쿠키 전송을 제한합니다.
Set-Cookie: session=abc; HttpOnly; Secure; SameSite=Lax옵션:
| 값 | 설명 |
|---|---|
| Strict | 같은 사이트 요청에서만 쿠키 전송 |
| Lax | 일부 top-level GET navigation에만 허용 |
| None | cross-site 전송 허용, Secure 필수 |
대부분의 일반 웹 서비스는 Lax 또는 민감도에 따라 Strict를 고려합니다.
방어 방법 3: Origin/Referer 검증
상태 변경 요청에서 Origin 또는 Referer 헤더가 신뢰할 수 있는 도메인인지 확인합니다.
Origin: https://app.example.com토큰 방식의 보조 방어로 사용할 수 있습니다.
방어 방법 4: JSON API와 커스텀 헤더
단순 HTML form으로는 Content-Type: application/json이나 커스텀 헤더를 쉽게 보낼 수 없습니다.
Content-Type: application/json
X-CSRF-Token: random-token다만 CORS 설정을 잘못 열어두면 방어 효과가 약해질 수 있습니다.
XSS와의 관계
XSS가 있으면 공격자가 페이지 안에서 CSRF 토큰을 읽거나 직접 요청을 보낼 수 있습니다. 따라서 CSRF 방어와 함께 XSS 방어도 필요합니다.
정리
CSRF는 "인증된 사용자의 브라우저가 원치 않는 상태 변경 요청을 보내는 공격"입니다. 방어는 CSRF Token, SameSite Cookie, Origin 검증을 조합하고, 상태 변경 요청에는 GET을 사용하지 않는 것이 기본입니다.
CSRF가 발생하는 조건
CSRF는 사용자가 로그인한 사이트의 인증 정보(cookie 등)가 브라우저에 자동으로 실려 가는 특성을 악용합니다. 공격 사이트가 사용자의 브라우저로 피해 사이트에 요청을 보내면, 서버는 정상 사용자의 요청처럼 오해할 수 있습니다.
<!-- 공격 사이트에 숨겨진 요청 -->
<form action="https://bank.example/transfer" method="POST">
<input name="to" value="attacker" />
<input name="amount" value="100000" />
</form>
<script>document.forms[0].submit()</script>방어 방법
- CSRF Token: 서버가 발급한 예측 불가능한 토큰을 폼/헤더에 포함합니다.
- SameSite Cookie:
Lax또는Strict로 cross-site 요청의 cookie 전송을 제한합니다. - Origin/Referer 검증: 민감한 요청에서 요청 출처를 확인합니다.
- GET 요청으로 상태를 변경하지 않습니다.
Set-Cookie: session=abc; HttpOnly; Secure; SameSite=LaxXSS와의 관계
CSRF 토큰이 있어도 XSS가 있으면 공격자가 토큰을 훔치거나 사용자의 권한으로 요청할 수 있습니다. 따라서 CSRF 방어와 XSS 방어는 함께 적용해야 합니다.