230317 TIL #35 CORS / 출처 Origin

김춘복·2023년 3월 17일
0

TIL : Today I Learned

목록 보기
35/571

230317 Today I Learned

미니프로젝트 시작. 오늘은 API 명세서와 와이어프레임을 짜고, github repository를 새로 팠고, 전체적인 서버 코드를 짰다. 오늘의 TIL에는 CORS의 개념에대해 정리해보려 한다.


참고 사이트

CORS

: Cross Origin Resource Sharing. 쉽게 말해 허락 받은 프론트엔드만 서버의 응답을 받을 수 있다는 개념. 프론트엔드와 백엔드 협업을 할 때, 각각 서버를 따로 띄우는데 CORS 설정을 하지 않으면 서로 상호작용할 수 없다. CORS는 추가 HTTP 헤더를 사용해서 한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 웹 애플리케이션은 리소스가 자신의 출처와 다를 때 교차출처 HTTP 요청을 실행한다.즉, 도메인이 다른 서버끼리 리소스를 주고받는 정책이다.

Origin?

: 출처. = Scheme + Host + Port. 하나라도 다르면 다른 Origin으로 판단.
https://sports.news.naver.com/news?oid=076&aid=0003983417#foo 의 URL에서

Scheme(일반적으로 Protocol) : "https://"
Host : "sports.news.naver.com"
Path : "/news"
QueryString : "?oid=076&aid=0003983417"
Fragment : "#foo"

로 나눌 수 있다. 여기서 Scheme과 Host, 그리고 :8080, :80 과 같은 Port까지 합친 것을 출처(Origin)이라고 한다.

CORS의 작동 방법

  • Preflight Request
    : 브라우저는 HTTP요청을 보낼때 사전에 OPTION 메서드를 이용한 HTTP 요청을 보내서 안전한지 확인해야하는데 이때 미리 전송한다고 해서 Preflight 요청이라 한다.
Access-Control-Request-Method: POST		// 요청하려는 메서드 정보
Access-Control-Request-Headers: X-PINGOTHER, Content-Type	// 요청에 담길 헤더 정보

그러면 서버는 응답으로 어떤걸 허용하는지에 대한 정보를 담아 돌려준다.

Access-Control-Allow-Origin: https://foo.example		// 허용된 origin 정보
Access-Control-Allow-Methods: POST, GET, OPTIONS		// 허용하는 메서드
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type //사용가능한 헤더 목록
Access-Control-Max-Age: 86400	//현재의 preflight request를 브라우저가 캐싱 가능한 최대 시간
  • Simple Request
    : 브라우저를 쓰지 않으면 preflight request를 보내지 않는다. ex) PostMan
    브라우저를 쓰더라도 생략하는 경우가 있는데 이를 Simple Request라 한다.
  • Credentialed Request
    : 자바스크립트의 fetch API를 사용하거나 Axios, Ajax 등을 사용할 때 서버로 쿠키를 함께 전송해야되는 경우가 있는데 요청에 쿠키가 담기면 Credentialed Request 허용이 되어야한다. 이때 서버쪽에서 응답 헤더에 Access-Control-Allow-Credentials: true를 보내줘야 브라우저에서 응답을 제대로 받을 수 있다. 여기서는 Access-Control-Allow-Origin 헤더 값이 와일드카드면 안되고 구체적인 Origin을 지정해야 한다.

서버에서 CORS 허용

public class WebSecurityConfig {
	//...생략
	 @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    	// ... 생략
    	http.cors(); // 이걸 넣어야 cors가 허용된다.
    }
    
    @Bean
    public CorsConfigurationSource corsConfigurationSource(){

        CorsConfiguration config = new CorsConfiguration();
        // 사전에 약속된 출처를 명시
        config.addAllowedOrigin("http://localhost:3000");
        // config.addAllowedOrigin("프론트 서버 출처?");

        // 특정 헤더를 클라이언트 측에서 사용할 수 있게 지정
        // 만약 지정하지 않는다면, Authorization 헤더 내의 토큰 값을 사용할 수 없음
        config.addExposedHeader(JwtUtil.AUTHORIZATION_HEADER);

        // 본 요청에 허용할 HTTP method(예비 요청에 대한 응답 헤더에 추가됨)
        config.addAllowedMethod("*");

        // 본 요청에 허용할 HTTP header(예비 요청에 대한 응답 헤더에 추가됨)
        config.addAllowedHeader("*");

        // 기본적으로는 브라우저에서 인증 관련 정보들을 요청 헤더에 담지 않는데,
        // 이 설정을 통해서 브라우저에서 인증 관련 정보들을 요청 헤더에 담을 수 있도록 해줍니다.
        config.setAllowCredentials(true);

        // 위의 allowCredentials 를 true로 하였을 때,
        // allowedOrigin의 값이 * (즉, 모두 허용)이 설정될 수 없도록 검증합니다.
        config.validateAllowCredentials();

        // 어떤 경로에 이 설정을 적용할 지 명시합니다. (여기서는 전체 경로)
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return source;
    }

일단 CustomSecurityConfig에서 필터체인에 http.cors();로 허용하고, 위와같이
CorsConfigurationSource를 만들어서 Cors를 허용하는 방법이 있다.
이 방법 말고 다른 방법으로도 Cors를 허용하는 방법이 있긴하다.

profile
Backend Dev / Data Engineer

0개의 댓글