스프링 시큐리티

Ch01. 스프링 시큐리티 기본 API 및 Filter 이해 - 사이트 간 요청 위조(CSRF, CsrfFilter)

webmaster 2022. 1. 15. 14:30
728x90

CSRF

  • 쇼핑몰 입장에서는 인증이 완료된 사용자의 쿠키가 있기 때문에 정상적인 인증이라고 생각한다.

CSRFFilter

  • 모든 요청에 랜덤하게 생성된 토큰을 HTTP 파라미터로 요구
  • 요청 시 전달되는 토큰 값과 서버에 저장된 실제 값과 비교한 후 만약 일치하지 않으면 요청은 실패한다
  • Client
    • <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    • HTTP 메소드 : PATCH, POST, PUT, DELETE
  • Spring Security
    • http.csrf() : 기본 활성화되어 있음
    • http.csrfhttp.csrf(). disabled() : 비활성화
  • @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
          throws ServletException, IOException {
       request.setAttribute(HttpServletResponse.class.getName(), response);
       CsrfToken csrfToken = this.tokenRepository.loadToken(request);
       boolean missingToken = (csrfToken == null);
       if (missingToken) {
          csrfToken = this.tokenRepository.generateToken(request);
          this.tokenRepository.saveToken(csrfToken, request, response);
       }
       request.setAttribute(CsrfToken.class.getName(), csrfToken);
       request.setAttribute(csrfToken.getParameterName(), csrfToken);
       if (!this.requireCsrfProtectionMatcher.matches(request)) {
          if (this.logger.isTraceEnabled()) {
             this.logger.trace("Did not protect against CSRF since request did not match "
                   + this.requireCsrfProtectionMatcher);
          }
          filterChain.doFilter(request, response);
          return;
       }
       String actualToken = request.getHeader(csrfToken.getHeaderName());
       if (actualToken == null) {
          actualToken = request.getParameter(csrfToken.getParameterName());
       }
       if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
          this.logger.debug(
                LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
          AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
                : new MissingCsrfTokenException(actualToken);
          this.accessDeniedHandler.handle(request, response, exception);
          return;
       }
       filterChain.doFilter(request, response);
    }
    CSRFFilter
  • CSRF 기능 설정
  • Thymeleaf와 같은 뷰 템플릿, Spring Form 태그를 사용하게 되면 기본으로 파라미터로 CSRF 토큰을 생성하여 준다.

 

728x90