SpringSecurity 사용 후 Post 요청마다 403에러를 만나다.

hanana·2023년 4월 22일

한줄요약 : SecurityConfig 파일에 http.csrf().disable()을 추가해주면 해결은 된다. 그러나...

화면에서 검색버튼을 url을 누르면 컨트롤러를 호출해야하는데, 컨트롤러에 들어가지 못하는 이슈가 발생했다.

문제의 코드는 다음과 같다.
search.html

<form action="/search" method="post">
    <input type="text" id="address_kakao" name="address" placeholder="어디서 한잔 할까요?">
    <div class="search-icon"></div>
    <div>
        <button type="submit" id="btn-save">Search</button>
    </div>
</form>

ApiController

@PostMapping("/search")
public String CheersSearch(String address) {
    log.info("[CheersController CheersSearch] - called");

    directionService.recommendPubs(address);
    return "cheers/search";
}

의도대로면 정상적으로 controller method에 들어와서 서비스 레이어를 호출해야 하는데, 아예 컨트롤러로 들어가지 못하는 현상이 발생했다.


시도해본 해결방법은 다음과 같다.


1. SecurityConfig를 수정하여 모든 요청에 대해서 접근을 허용했다.

@Bean
public SecurityFilterChain securityFilterChain(
        HttpSecurity http,
        OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService) throws Exception {
    return http
            .authorizeHttpRequests(auth -> auth
                            .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                            .mvcMatchers(HttpMethod.GET,
                                    "/", "/index", "/users/login").permitAll()
                            .anyRequest().permitAll()
            )
            .logout(logout -> logout.logoutSuccessUrl("/"))
            .oauth2Login(oAuth -> oAuth
                    .userInfoEndpoint(userInfo -> userInfo.userService(oAuth2UserService)
                    )
            )
            .build();
}

첫번째로 든 생각은 접근 권한이 제대로 주어지지 않았다는 생각이였다.

이번 프로젝트를 진행하면서 처음으로 Oauth2 인증방식을 적용해보았고, 해당부분에서 좌충우돌 기능을 구현하였기 때문에 로그인까지는 어떻게 가능하나, 권한 적용을 제대로 못한것이 아닐까? 싶어서 모든 요청에 permitAll()을 적용하였다.
그러나, 여전히 Controller에서 response를 못받는 현상이 나아지지 않았다.


2. 두번째로 Intercepter에서 어떠한 이유로 인하여 요청이 거부되는것이 아닌가 판단하여 Intercepter에 log를 남겨보았다.
 @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    log.info("[ExceptionInterceptor preHandle]");
    return true;
}
...


너무나 조용한 Console창의 모습...
애초에 Interceptor자체에 접근조차 못하고 있었다.


3. 아예 스프링 시큐리티와 인터셉터의 @Configuration 설정을 빼보았다.

무수한 redirection의 항연이...
후에 조금 더 공부해야겠지만, 이미 Oauth와 연동되는 시점부터 SecurityConfig와는 떼려야 뗄 수 없는 사이가 된 것으로 추측된다.


4. 한참을 고민하다가 크롬 개발자 도구로 와서 보니 다음과 같은 에러가 찍혀있었다.

사실 예전에 한번 다뤄본 적 있는 이슈였다.
SpringSecurity가 기본적으로 csrf(서버간 위변조 공격)에 대한 보안을 자동으로 실행해주기 때문에 Get요청에 대해서는 정상적인 호출이 되나, Post요청에 대해서는 어떠한 이유로 요청을 거부하는 403 forbidden에러를 뱉는 현상이였다.

@Bean
public SecurityFilterChain securityFilterChain(
        HttpSecurity http,
        OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService) throws Exception {
    return http
            .authorizeHttpRequests(auth -> auth
                            .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                            .mvcMatchers(HttpMethod.GET,
                                    "/", "/index", "/users/login").permitAll()
                            .anyRequest().permitAll()
            )
            .logout(logout -> logout.logoutSuccessUrl("/"))
            .oauth2Login(oAuth -> oAuth
                    .userInfoEndpoint(userInfo -> userInfo.userService(oAuth2UserService)
                    )
            )
            .csrf().disabled();
            .build();
}

SecurityConfig 클래스에 http.csrf().disable()로 설정해주어서 해당 문제를 해결했다.
과거에도 이런식으로 처리하고나서, 프로젝트를 마치고 회고란에

'문제를 해결하긴 하였으나, 문제를 해결하기 위해서 스프링이 기본으로 제공하는 보안기능을 disable() 처리하는것이 과연 올바른 것인지 모르겠다.
인터셉터에서 추가적인 검증을 진행하거나, 쿠키대신 JWT를 이용하는 방식 등으로 해결이 가능하다고 한다. 해당 기능까지 구현하면 좋겠지만, 아직은 배움이 부족해서 넘어가지만 배움을 계속해서 저 이슈를 확실하게 다뤄보고 싶다.' 라는 글을 남겼었다.


현재 진행중인 프로젝트는 Oauth2 인증기능을 사용하고, 조금만 더 찾아보면 jwt까지도 사용해 볼 수 있을것 같다.
저번에 다루지 못했던 이슈를 이번엔 다뤄보고싶다.


'목표가 있고 기대를 한다면, 그건 되게 재밌는 일이다.'
회사의 회장님이 티타임 시간에 해주신 말씀이다.
정말 기대가 되고 재미난 일이 될 것 같다.
재밌게 한번 도전 해보고 어느덧 한발 더 성장했음을 프로젝트로 나타내고 싶다.

profile
성숙해지려고 노력하지 않으면 성숙하기까지 매우 많은 시간이 걸린다.

1개의 댓글

comment-user-thumbnail
2025년 2월 8일

잘 읽었습니다. 감사합니다 !

답글 달기