CSRF 공격이란?
CSRF 공격이란 사용자가 로그인하면 세션ID가 쿠키로 저장되는데, 서버는 세션 ID로 사용자를 인증하고 구분하여 요청을 수행한다. 쿠키는 브라우저에 저장되기 때문에 공격자가 임의의 폼을 생성한 링크를 사용자에게 클릭하도록 유도하면 브라우저는 쿠키에 저장된 세션ID와 공격자의 폼을 함께 서버로 전송한다. 이 때 폼은 공격자가 원하는 행동으로 설계해둔다. (은행송금, 개인정보탈취 등)
더불어 사용자가 진짜로 요청한 것인지 임의로 공격자가 설계한 공격인 것인지 구분하기도 어렵다.
공격자는 이메일, 악성 웹사이트, 광고 배너 등을 통해 사용자가 악성 링크를 클릭하게 유도할 수 있다.
CSRF 공격을 방어하는 방법
1. CSRF 토큰을 사용한다.
스프링 MVC, 장고 MTV 같은 프레임워크를 사용하면 csrf 토큰을 지원한다. 그 중에 HTML의 폼에 Hidden 필드에 CSRF 토큰을 저장하는 방식으로 사용한다. 또는 HTML이 아닌 쿠키에 저장하기도 하는데 이때는 Http Only, Secure, SameSite 같은 보안 설정을 꼭 해주어야 한다.
form 이 아닌 ajax, async await 같이 비동기 요청을 보낼 때도 HTTP 헤더에 CSRF 토큰값을 꼭 포함시켜야한다.
서버는 요청을 받을 때마다 세션ID + CSRF 토큰을 함께 검증하여 사용자가 요청한 것이 맞는지 확인한다.
2. JWT 토큰 인증을 사용한다.
JWT 토큰 인증은 Stateless 즉 무연결성이기 때문에 세션을 따로 관리하지 않는다. 이에 브라우저 쿠키에 세션ID가 저장될 일도 없어서 CSRF 공격으로부터 비교적 안전하다.
서버는 요청을 받을 때마다 JWT 토큰을 확인하여 사용자를 검증한다. 브라우저가 쿠키를 자동으로 포함하는 것과 달리, 로컬 스토리지나 세션 스토리지의 JWT는 브라우저가 자동으로 포함하지 않는다.
다만 JWT를 쿠키에 보관해야한다면 보안을 더욱 철저히 해야하고, CSRF와 다른 공격인 XSS 공격을 통해 자바스크립트가 로컬 스토리지에 저장된 JWT를 탈취할 수도 있다.
이에 XSS 공격 방지를 위해 애플리케이션 코드에서 입력 검증(Input Validation) 및 출력 인코딩(Output Encoding)을 철저히 해야한다.