CSRF 공격 원리와 웹 애플리케이션 방어 전략
CSRF의 요청 위조 구조와 XSS와의 차이, 토큰·SameSite 쿠키·재인증·헤더 검증을 활용한 웹 보안 대응 방법을 정리한다.
2026-08-14 · 최초 발행 2025-05-29
로그인 상태를 겨냥하는 요청 위조
CSRF(Cross-Site Request Forgery)는 인증을 마친 사용자의 권한을 빌려 공격자가 원하는 작업을 수행하게 만드는 웹 보안 취약점이다. 사용자는 자신의 의사와 무관하게 삭제, 수정, 등록 같은 요청을 실행하게 될 수 있다.
공격은 브라우저가 이미 저장한 인증 정보와 서버의 신뢰 관계를 이용한다. 사용자가 대상 사이트에 로그인해 쿠키나 세션을 보유한 상태에서 악성 링크나 웹페이지를 열면, 브라우저는 요청과 함께 인증 쿠키를 보낼 수 있다. 서버가 이를 정상 요청으로 받아들이면 공격자가 유도한 작업이 처리된다.
요청이 위조되는 장면
인터넷 뱅킹에 로그인한 사용자가 공격자가 만든 페이지를 방문했을 때, 공격자의 계좌로 송금하는 요청이 자동 실행될 수 있다.
<img
src="https://bank.example.com/transfer?amount=1000000&to=attacker"
width="0"
height="0"
/>
이 코드는 이미지 로딩으로 보이게 하면서 사용자가 알지 못한 채 송금 요청을 발생시킨다.
계정 정보 변경도 같은 방식으로 유도할 수 있다. 예를 들어 공격자는 사용자의 이메일이나 비밀번호를 바꾸는 요청을 제출하게 만들 수 있다.
<form id="hack-form" action="https://example.com/change-email" method="POST">
<input type="hidden" name="new_email" value="hacker@evil.com" />
</form>
<script>
document.getElementById("hack-form").submit();
</script>
CSRF와 XSS가 노리는 지점
CSRF와 XSS는 모두 웹 보안에서 자주 다뤄지지만, 공격이 성립하는 방식과 목적은 다르다.
| 구분 | CSRF | XSS |
|---|---|---|
| 정의 | 인증된 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 수행하게 하는 공격 | 웹사이트에 악의적인 스크립트를 삽입하여 사용자 정보를 탈취하는 공격 |
| 주 목적 | 인증된 사용자의 권한 악용 | 사용자 인증 정보 탈취 |
| 공격 방향 | 인증된 사용자가 서버를 공격 | 클라이언트에서 인증정보를 공격자에게 전송 |
| 핵심 차이 | 인증 상태를 이용 | 스크립트 실행을 이용 |
권한이 있는 요청이 만드는 피해
CSRF가 성공하면 민감한 개인정보가 공격자에게 전송될 수 있고, 사용자 데이터가 변경될 수 있다. 같은 요청이 반복 실행되면 시스템 과부하로 이어질 가능성도 있다.
관리자 권한을 가진 사용자가 공격 대상이면 시스템 전체가 위험해질 수 있다. 금융 거래가 조작되는 경우에는 직접적인 금전적 손실도 발생한다.
요청의 출처를 확인하는 방어 수단
CSRF 토큰은 서버가 생성한 고유 토큰을 폼 제출에 포함해 요청 출처를 검증하는 방식이다.
<form action="/transfer" method="post">
<input type="hidden" name="csrf_token" value="랜덤_생성_토큰" />
<!-- 기타 폼 필드 -->
<button type="submit">전송</button>
</form>
서버는 요청에 담긴 CSRF 토큰이 자신이 생성한 토큰과 일치하는지 확인한다.
SameSite 쿠키 속성도 크로스 사이트 요청에서 쿠키 전송을 제한하는 데 사용한다. Strict나 Lax로 설정할 수 있다.
Set-Cookie: sessionid=abc123; SameSite=Strict;
비밀번호 변경이나 송금처럼 중요한 작업에는 비밀번호 재확인 또는 2차 인증을 요구할 수 있다. HTTP Referer 헤더를 검사해 신뢰할 수 있는 출처의 요청인지 확인하는 방법도 있다.
# 백엔드 코드 예시 (Python)
def process_request(request):
referer = request.headers.get('Referer', '')
if not referer.startswith('https://trusted-domain.com'):
return 'CSRF 공격 의심됨', 403
# 정상 처리 로직
AJAX 요청에서는 커스텀 헤더를 추가해 검증할 수 있다. 브라우저의 same-origin 정책 때문에 외부 사이트에서는 커스텀 헤더를 추가할 수 없다.
// 클라이언트 측 AJAX 요청 예시
fetch("/api/data", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest", // 커스텀 헤더
},
body: JSON.stringify(data),
});
보호 체계를 점검하는 방법
로그인한 뒤 중요 기능을 식별하고, 해당 요청을 다른 도메인에서 트리거할 수 있는지 수동으로 테스트한다. OWASP ZAP, Burp Suite 같은 보안 테스트 도구를 활용하는 방법도 있다.
다양한 CSRF 공격 벡터를 대상으로 보호 메커니즘을 점검하면 방어 체계의 견고성을 평가할 수 있다.
Spring Security 설정 예시
Spring Security는 기본적으로 CSRF 보호 기능을 제공한다.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
// 기타 보안 설정
}
}
CSRF는 사용자의 인증 상태를 악용한다. 웹 애플리케이션에서는 CSRF 토큰, SameSite 쿠키, 사용자 재인증 같은 보호 수단을 적용해야 하며, 금융 거래나 개인정보 변경 기능에는 더 강화된 보안 조치가 요구된다.