스프링 부트와 aws로 구현하는 웹서비스 책을 따라하다 보니, 시큐리티 부분에 대해 잘 모른채 책에서 시키는 대로 구현하는데 집중하였다.
문제는 내가 책과 달리 데이터베이스를 h2가 아닌 MySQL로 설정하였다는 것에서 시작하는데...
.csrf().disable().headers().frameOptions().disable()
SecurityConfig의 이 설정!
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
@Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable().headers().frameOptions().disable().and()
책에 써있기로는 "h2-console 화면을 사용하기 위해 해당 옵션들을 disable한다" 라고만 간단하게 쓰여있었기에.. 나는 h2안쓰니까~ 하면서 쿨하게 주석처리 해주었습니다.
그런데, 댓글 기능을 추가하기 위해서 전체적인 기능을 확인하려는데 글 등록시 계속 403 에러가 발생하였습니다.
뭐가 문젠지 한참 헤매다가 해당 설정의 주석을 해제해 주었는데 더이상 403에러가 발생하지 않습니다.
이것들이 무엇인지 알아보도록 하겠습니다.
<img src= "https://bank.service.com/transfer?.amount=10000&.dst=도둑">
이러한 csrf공격을 막기 위하여 스프링은
다만, 스프링 시큐리티는 세션 쿠키를 직접적으로 제어하지 않으므로, SameSite속성에 대해 지원하지 않습니다.
동기화 토큰 패턴 은 세션 쿠키 외에 각 HTTP요청에 CSRF토큰이라는 보안 무작위 생성 값이 있어야 함을 요구하는 것입니다.
CSRF토큰이 없거나, 실제 CSRF토큰과 일치하지 않는다면 요청을 거부합니다.
HTTP 매개변수, 또는 HTTP 헤더 CSRF토큰을 포함할 것이 요구됩니다.
제가 해왔던 요청에는 CSRF토큰이 없습니다. 그래서 계속 문제가 발생했던 것입니다.
이 csrf속성을 꺼주지 않아서 문제가 발생한 듯 보입니다. 그런데 csrf속성을 꺼주지 않으면 문제가 발생하지 않을까요??
When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.
스프링 공식 문서에 따르면 논-브라우저 클라이언트(wget,curl같은 것)들만이 사용하는 서비스라면 CSRF 속성을 꺼도 좋다고 합니다.
근데 제가 생각하기엔, 이 게시판은 언젠가 브라우저 클라이언트가 사용하게 될 것이고, 그러면 CSRF가 필요한 것 아닌가? 하는 의문이 생겼습니다.
저와 같은 의문을 가진 사람이 있군요
https://stackoverflow.com/questions/52363487/what-is-the-reason-to-disable-csrf-in-spring-boot-web-application
이분 말에 따르면 현재는 jwt등의 토큰 메커니즘을 사용하고 있지 않은 저의 서비스는 csrf가 필요한듯합니다.
튜토리얼을 쉽게 만드려고 그렇다는 의견도 있군요
이 링크의 첫번째 답변이 큰 도움이 됐습니다
답변에 따르면
현재의 세션 기반 인증은 쿠키를 사용합니다.
No Cookies도 아니고, stateless 하지 않기에 csrf에 취약합니다.
왜 저자분께서 CSRF를 disable하셨는지는...잘 모르겠습니다. 컴팩트한 책이다보니 진행의 용이함을 위해 빼셨을 수도 있고, 제가 모르는 무언가가 있을 수도 있습니다.
아무튼! 제가 이해한 바로는 현재의 세션 인증 방식으로는 CSRF 방어가 필요합니다.
다만,
1. 아직 로컬에서만 개발중인 단계이고
2. 시큐리티에 대한 이해가 충분하지 않은 상태이니
이대로 두겠습니다.
추후에 JWT기반 인증으로 바꾸는 과정을 거칠것입니다.
마지막으로, disable() 뒤의 headers().frameOptions().disable()는 무엇일까요?
해당 스택오버플로 를 참고했습니다
그러나, h2 콘솔의 ui는 (책에서는 h2콘솔을 사용) frame 을 사용하고 있기에, X프레임 옵션을 끄지 않는다면 에러가 날 것입니다.
h2콘솔을 사용하기 위해 해당 설정을 꺼준듯 보입니다. 당연히 공격에는 취약할 것입니다.
참고 https://ko.wikipedia.org/wiki/%EC%82%AC%EC%9D%B4%ED%8A%B8_%EA%B0%84_%EC%9A%94%EC%B2%AD_%EC%9C%84%EC%A1%B0
https://www.synopsys.com/glossary/what-is-csrf.html
https://rusyasoft.github.io/java/2019/02/15/spring-security-csrf-from-context/
https://zzang9ha.tistory.com/341
https://docs.spring.io/spring-security/site/docs/5.3.x/reference/html5/#csrf
https://www.quora.com/What-are-non-browser-clients