Spring Security는 기본적으로 csrf 공격에 대한 방어 기능을 제공한다. csrf가 뭐길래 방어 기능까지 제공할까?
사이트 간 요청 위조(Cross-site request forgery, CSRF)는 웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격을 말한다. - 위키백과
그러니까, 나는 A라는 행동을 하기 싫은데, 강제로 A라는 행동을 취하게 되는 것이다. 예를 들어, 흔히 만나는 스팸 메일의 링크를 누르면 타인의 계좌에 송금되는 경우가 csrf의 예시라고 생각할 수 있겠다. 링크에 송금 링크를 걸어두고, 링크를 클릭하면 송금이 일어나게 되는 것이다. 송금 서비스는 송금 요청이 왔으니 이를 수행할 뿐이다.
Spring Security에서는 REST API를 사용하는 경우에는 stateless하기 때문에 csrf를 사용하지 않아도 된다고 한다. 우리는 REST API를 사용한다가 아니라, stateless하다에 집중해야한다. 만약 REST API를 사용한다 해도, 사용한 인증정보를 계속해서 유지하는 전략을 선택한다면 (예를 들어 세션 인증), 여전히 csrf공격에 취약하다. 왜 그럴까?
csrf공격의 핵심은 '서버가 사용자를 신뢰한다'는 점에 있다. 그러니까, 서버는 클라이언트로부터 들어온 요청을 일단 믿고 본다. 여기에서 문제가 발생한다. 나한테 요청을 보낸 사용자는 '이미 내가 인정한 사용자다' 라는 데에 있다. 왜 이렇게 멍청하게 하냐고? 아니 이 사람이 나랑 칼라로 연결돼있다니까요? 지금 이 사람 로그인 한 사람이고, 이 사람이 보낸 요청인데 뭐 어쩌라는거임...
그럼 이런 공격을 막고 싶으면 어떻게 하면 될까? 서버에서 사용자와의 상태를 유지하지 않고, 요청이 적절한지 검증하면 된다. 사용자의 요청이 오면 일단 의심하는 것이다. 사실 의심이랄 것도 없다. stateless한 방식에서는, 사용자가 지금 우리 서비스를 이용하는지를 모르고 있다. 모르는데 어떻게 믿어요. 이렇게 csrf 공격을 막는 방법을 Spring Security에서는 CSRFToken을 발급하는 방식으로 제공하고 있다. 흠,,, 토큰? 그럼 이 토큰을 우리가 사용하면 안되나? 당연히 된다. JWT를 사용하여 csrf에 대한 대처를 할 수 있다.
서버에서는 JWT를 만들어 클라이언트에 전달한다. 클라이언트는 해당 토큰에 담긴 정보를 저장한다. 그리고 요청을 보낼 때 함께 전송한다. 서버에서는 이렇게 온 정보를 서버에서 가진 key를 활용해 해석하고, 적절하면 요청을 들어준다. 아니면 거절하고.
그런데 이렇게 보니까 좀 이상한데? 그냥 JWT에 담긴 정보를 해커가 뺏어가면 다 똑같은 거 아녀? 라는 생각에 이 내용을 3시간 정도 찾아봤습니다... 결국 핵심은 JWT를 어디에 저장할 것인가? 에 있었다. 그런데, 서버는 JWT를 저장안하잖아. 그냥 뚝딱 만들어서 보내면 끝인데... 그렇다. 결국 클라이언트에서 JWT를 어떻게 저장할지를 고민해야 하는 것이다.
여러 글들을 찾아본 끝에 정보를 나눠 담는 것이 베스트라고 일단락 지었다. Access Token의 정보는 브라우저의 로컬 변수에 저장하고 Refresh Token은 httpOnly 쿠키에 저장하는 것이다. 이렇게 설정한 결과는... 링크에서 확인하실 수 있다.
간단하게 시작한 공부가 꽤 딥해졌다. 보안에 관해서 이렇게 깊이 탐색했던 적이 있던가... 세션 방식의 문제점이 단순히 서버를 너무 뒤진다 이외에도 있다는 점도 알게 되었고, csrf공격과 xss공격에 대해서, 그리고 우리는 생각보다 보안이 취약한 세상에 살고 있다는 점도 알게 되었고... 아무튼 이해에 가장 크게 도움이 됐던 글의 링크는 하단에 남겨 놓는다. 같이 공부해요!
참고 자료
밸덩 : A Guide to CSRF Protection in Spring Security
https://www.baeldung.com/spring-security-csrf
밸덩 : CSRF With Stateless REST API
https://www.baeldung.com/csrf-stateless-rest-api
심재철님 블로그
https://simsimjae.tistory.com/482
토큰을 어디에 저장해야 안전할까
이 글은 독자가 JWT, 세션등에 대한 이해를 갖고 있다는 전제하에 정리 차원에서 작성한 글입니다. TL;DR 1. 리프레시 토큰은 HTTP ONLY SECURE 쿠키에 저장하자. 2. 액세스 토큰은 프로그램상 자바스크
simsimjae.tistory.com
코딩하는 경제학도님 블로그
https://ssocoit.tistory.com/235
[보안] XSS와 CSRF의 차이
얼마 전에 퀘이사존에서 특정 글을 보면 회원이 탈퇴되는 일이 있었다고 합니다. 금방 조치가 되긴 했지만 도대체 이걸 어떻게 했을까 싶기도 하고, 왜 사이트에서는 이걸 막지 못했을까 생각하
ssocoit.tistory.com
'Programming > Study' 카테고리의 다른 글
테스트를 실행은 하고 싶은데 빌드에서는 제외하고 싶을 때 (1) | 2023.12.07 |
---|---|
Spring Security의 인증 처리 흐름 (0) | 2023.12.06 |
PasswordEncoder의 작동 원리와 테스트하기 어려운 이유 (0) | 2023.12.04 |
Querydsl 사용해보기 - 검색 기능 만들기 (1) | 2023.11.30 |
HTTP PUT 메서드로 자원을 수정할 때의 응답 : 200 vs 201 vs 202 (0) | 2023.11.27 |
댓글