CSRF는 사용자가 로그인한 상태를 악용해, 공격자가 사용자의 브라우저를 통해 원하지 않는 요청을 서버에 보내는 공격이다.
사용자는 자신이 의도하지 않았지만, 브라우저는 정상 요청으로 간주하고 서버에 전달한다.
ex:
사용자가 로그인된 상태에서 악성 웹사이트에 접속하면, 그 사이트가 <form> 또는 <img> 태그 등을 통해 자동으로 POST 요청을 발생시켜 사용자의 계정을 이용해 게시글 작성, 비밀번호 변경 등 민감한 요청을 수행할 수 있다.
방지 방법:
Spring Security는 기본적으로 CSRF 방어를 활성화한다. 서버는 요청 시 CSRF 토큰을 요구하며, 이 토큰은 세션 또는 쿠키에 저장되고, 클라이언트가 hidden 필드나 헤더를 통해 전송한다. 서버는 요청에 포함된 토큰과 저장된 값을 비교해 검증하며, 불일치할 경우 요청을 거부한다.
XSS는 사용자의 입력값에 포함된 스크립트가 필터링되지 않고 실행되는 공격이다. 공격자는 이를 통해 쿠키 탈취, 세션 탈취, 악성 행동 유도 등의 피해를 일으킬 수 있다.
예시:
댓글 입력란에 와 같은 코드를 삽입하면, 그 댓글을 보는 사용자의 브라우저에서 해당 스크립트가 실행되어 쿠키나 인증 정보를 외부로 전송할 수 있다.
방지 방법:
사용자 입력을 출력할 때 반드시 HTML 이스케이프 처리를 해야 한다. Spring에서는 th:text, @ResponseBody 등이 자동으로 이스케이프 처리를 수행한다. 추가로, CSP(Content Security Policy)를 통해 외부 스크립트 실행을 제한하는 것도 도움이 된다.
세션 고정은 공격자가 미리 발급받은 세션 ID를 피해자에게 사용하게 하여, 공격자가 인증된 세션에 접근하도록 유도하는 공격이다.
예시:
공격자가 JSESSIONID=abc123을 포함한 링크를 피해자에게 전송하고, 피해자가 로그인하면 해당 세션 ID가 계속 유지되어 공격자가 동일한 세션을 사용할 수 있게 된다.
방지 방법:
Spring Security는 기본적으로 로그인 성공 시 세션 ID를 강제로 재발급한다. 설정상 sessionManagement().sessionFixation().migrateSession()을 통해 새 세션으로 전환되며, 기존 세션 ID는 무효화된다.
JWT는 클라이언트에 저장되는 토큰이므로, 탈취되었을 경우 제3자가 그대로 사용하여 인증을 우회할 수 있는 위험이 있다.
예시:
브라우저의 로컬스토리지에 저장된 JWT를 XSS 공격을 통해 탈취한 뒤, 공격자가 해당 토큰을 Authorization 헤더에 담아 서버에 요청을 보내면 정상적인 사용자로 인식되어 접근이 가능하다.
방지 방법:
Access Token은 메모리에 저장하거나 HttpOnly 쿠키에 보관하고, Refresh Token은 반드시 HttpOnly + Secure 속성의 쿠키에 저장해야 한다. 또한 HTTPS로 전송하고, 토큰 만료 시간을 짧게 설정하여 주기적인 재발급을 유도한다. 서버는 Refresh Token을 상태 기반으로 관리하거나, 블랙리스트를 운영하여 탈취된 토큰의 재사용을 차단할 수 있다.