@Test
@DisplayName("해당 게시물에 권한 없는 유저가 질문을 삭제")
@WithMockUser(SecurityContextUtils.ANONYMOUS_USER_ID_STRING)
void unAuthorizedUserDeleteQuestion() throws Exception {
Long targetQuestionId = 1L;
when(questionService.getAuthorId(targetQuestionId)).thenReturn(Long.valueOf(AUTHORIZED_USER));
mvc.perform(delete("/questions/"+ targetQuestionId))
.andExpect(status().isUnauthorized());
}
이러한 상황에서 위의 테스트코드는 fail이다.
실행시켜보면 status가 403이 나온다. (권한있는 유저가 질문을 삭제하는 경우에도 403이 나온다.)
그 이유는 csrf설정을 추가하지 않았기 때문이다.
csrf에 관한 깊은 설명은 다음에 하기로 하고 간단한 설명부터 해보겠다.
csrf(Cross Site Request Forgery)의 동작 원리는
사용자가 보안이 취약한 사이트에 로그인함 -> jwt 토큰 담긴 쿠키 발급됨
해킹범이 보안이 취약한 사이트에 악성 링크를 심음
사용자가 악성링크를 들어감
악성링크에는 로그인시 발급받은 쿠키가 들어가 있음
해킹범이 해당 쿠키를 이용하여 우리 서버에 직접 공격
이런식으로 탈취가 일어난다.
우리 사이트에서 발급받은 쿠키는 꽤나 보안적으로 안전하다고 생각했다.
HttpOnly 설정을 활용하여 HTTP통신에서만 쿠키에 접근이 가능하게함. (자바스크립트를 활용한 XSS방지)
Secure 설정을 활용하여 Http 통신에서는 쿠키 통신 불가능
도메인 설정을 통해, 특정 도메인에서만 쿠키가 유효
완벽하다고 생각했지만, 도메인 설정 이 완벽하지 않았다. 서브도메인을 다르게하면 고대로 탈취될 수 있기 때문이다.
Spring Security에서 보통 많은 사람들이 csrf 설정을 막는데,
그 이유는 현재 대다수의 통신 방법인 REST api 통신에서는 정보들이 모두 stateless하기 때문이다. 무엇인가 권한이 필요한 요청을 하기 위해서는 요청에 필요한 인증 정보를(OAuth2, jwt토큰 등)을 포함시킨다.
하지만 쿠키를 사용하여 인증하는 경우 csrf설정을 끄면 안된다.
이유를 알고 csrf를 끄자.
아무튼.. 일단 저 테스트는 MvcTest만을 위한것이므로, 기본적으로 csrf설정을 config로 했다고 해도, MvcTest만을 위한 스프링 빈만 주입시켜서, 해당 설정이 주입되지 않는다.
따라서 csrf설정을 해주자.
@Test
@DisplayName("해당 게시물에 권한 없는 유저가 질문을 삭제")
@WithMockUser(SecurityContextUtils.ANONYMOUS_USER_ID_STRING)
void unAuthorizedUserDeleteQuestion() throws Exception {
Long targetQuestionId = 1L;
when(questionService.getAuthorId(targetQuestionId)).thenReturn(Long.valueOf(AUTHORIZED_USER));
mvc.perform(delete("/questions/"+ targetQuestionId)
.with(csrf()))
.andExpect(status().isUnauthorized());
}