본문 바로가기
Web/Spring

[Spring/Java] CORS 이슈 처리 방법

by char_lie 2023. 11. 21.
반응형

Spring을 사용하여 프로젝트를 진행하는 과정에서 CORS 이슈가 발생했고, 이 과정에서 로컬에선 정상적으로 CORS처리가 됐으나, 배포 환경에서는 오류가 발생하여 원인을 찾느라 애먹었다.

결론부터 말하자면, 내가 작성한 부분이 원인이 아닌 MSA구조로 작성하는 과정에서 게이트웨이에서 CORS가 발생했던 이슈였다. 게이트웨이에서 CORS 처리를 해줬더니 정상 동작했다.

CORS(Cross-Origin Resource Sharing)

CORS란?

보안 이슈로 인해 웹 페이지에서 리소스에 대한 Cross-origin 요청을 관리하기 위한 보안 메커니즘으로 서버의 동의가 된 요청들에 대해서만 요청할 수 있도록 제한하는 것

모든 데이터 요청을 허용할 경우 데이터 무결성이 보장되지 않으며 다른 사이트에서 원래 사이트를 흉내 내게 되어 로그인했던 세션 탈취 등 악의적으로 정보를 추출하는 등의 공격을 할 수 있음.

포트 번호에 따라 다른 출처로 간주되어 CORS에 걸릴 수 있음.

 

이미지 출처 : https://www.memedroid.com/memes/detail/2429165

 

여담으로 CORS에 대해 찾아보다가 IE(Internet Explore)는 출처 비교 시 포트 번호를 완전 무시하는 브라우저라고 하더라.

해결 방법

해당 origin에 대해 CORS 서버 요청을 허용해 주면 된다. Spring에서 이를 위해 Filter기능을 사용할 수 있고, 코드는 아래와 같이 적용했다.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Value("#{'${cors.origins}'.split(',')}")
    private List<String> origins;


    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        String origin = request.getHeader("Origin");
        if (origin != null && origins.contains(origin)) {
            response.setHeader("Access-Control-Allow-Origin", origin);
        }
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, Authorization");

        if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        }else {
            chain.doFilter(req, res);
        }
    }
}

 

각각의 요청 허용에 대한 내용은 아래와 같다.

  • Access-Control-Allow-Origin 헤더를 설정
  • Access-Control-Allow-Credentials는 자격 증명을 사용할 수 있도록 허용 여부를 판단
  • Access-Control-Allow-Methods는 허용된 HTTP 메서드를 지정
  • Access-Control-Max-Age는 브라우저가 Preflight 요청 결과를 캐시 할 시간을 설정
  • Access-Control-Allow-Headers는 허용된 HTTP 헤더를 지정

이를 위해 도메인 등이 노축되지 않도록 아래와 같은 형태로 추가해서 사용했다.

// application.yml
cors:
  origins: http://localhost:3000,다른도메인

 

이 과정을 통해 정상적으로 CORS처리가 됨을 확인할 수 있었다.

반응형

댓글