[Spring] CORS 알아보기

전현준·2024년 1월 7일
0

Spring

목록 보기
6/17
post-thumbnail

📢 CORS?


Cross-Origin-Resource-Sharing 의 줄임말로, 교차 출처 리소스 공유 라는 뜻이다.

사진 출처 : CORS의 기본 개념과 동작 방식(부제: Preflight 요청이란?)

  • 브라우저에서 요청시 (Origin)이 다르면 발생하는 브라우저 정책
  • CORS는 허가되지 않은 외부 요청을 막고, 악의적으로 정보가 탈취되는 것을 막음!

💻 cross-origin

cross-origin은 다음 중 한가지라도 다른 경우를 말함. 이 셋 중 하나라도 다르면 CORS 가 발생한다.

  • 프로토콜 : http / https 두 프로토콜은 다르다.
  • 도메인 (Host) : localhost / naver.com 두개는 다르다.
  • Port : 8080 / 3000은 다르다.

💻 Spring 에서는 CORS가 언제 발생함?

프로젝트 하면 Backend는 Java Spring으로 개발하고 Frontend를 React로 개발할 때
REST API 형태로 개발할 것이다.

HTTP 통신을 하게 되면 Spring의 톰캣은 localhost:8080 / React : localhost:3000 으로 다르다.

이때 서버로 데이터를 요청해야 하는데, 이때 CORS가 발생할 가능성이 높다.


⛔ CORS 동작 방식


  • Simple Request : 단순 요청
  • Preflight Request : 예비 요청
  • Credential Request : 인증된 요청

🥇 Simple Request

단순히 요청을 보내는 방법이다.

Client가 요청을 보내면 ServerAccess-Control-Allow-Origin을 헤더에 붙여 Response를 한다.

그럼 Access-Control-Allow-Origin를 판단하여 CORS를 검사한다.

Access-Control-Allow-Origin : 서버에서 허용된 Origin


사진 출처 : CORS의 기본 개념과 동작 방식(부제: Preflight 요청이란?)

위 사진은 Access-Control-Allow-Origin : * 으로 설정되어 있으니,
모든 도메인을 허가하겠다는 뜻이다.


✅ 예시

아래 상황을 한번 보겠다.

  • 요청한 Client : 1.2.3.4:8080
  • Server의 Access-Control-Allow-Origin : a.com

Client의 도메인과 Server가 허용한 도메인은 서로 다르다.

이 상황에서 HTTP 응답은 200 OK이지만 ❗ CORS 정책이 발생한다!

✅ 발동 조건

  • GET, HEAD 요청
  • Content-Type 헤더가 다음과 같은 POST 요청
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안됨.

하지만 나는 REST API의 형태로 Content-Typeapplication/json이기 때문에 Preflight로 처리 된다.


🥈 Preflight Request

서버에 예비 요청을 보내는 것, Preflight 요청을 받아서 비교하고, 허가되지 않은 요청이면 CORS 발생

미리 이 예비 요청은 OPTIONS 방식으로 보낸다.

만약 CORS가 걸리는 요청인데 API 호출하면 불필요한 리소스를 낭비하기에 예비 요청을 통해서 불필요한 리소스를 줄이는 것이다.


🥉 Credentialed Request

인증정보를 포함한 요청, 보안을 강화하고 싶을 때 헤더에 인증 정보를 넣어 보내는 방식.

서버에서 설정

  1. 응답 헤더에 Access-Control-Allow-Credentials : true 를 추가한다.
  2. 응답 헤더의 Access-Control-Allow-Origin 을 정확하게 설정한다. * 로 설정 X

나의 경우에는 JWT 토큰을 담아 보안을 강화했다.

헤더에 Authorization에 토큰을 담아 요청을 보낸다.


🍃 Spring에서 CORS 맛보기


💾 CorsConfig.java

여기서는 간단하게 세팅할 수 있는 방법으로 살펴보겠다. 모든 도메인을 허가하는 방식이다.

본인에게 필요하게 변경하여 사용하면 되겠다.

  • setAllowCredentials                              : false ➜ Credentials 방식 사용 안함
  • setAllowOrigins(Arrays.asList("*"));     : 모든 도메인 허용
  • setAllowedMethods                                 : 허가할 메소드들
  • setAllowedHeaders                                 : HTTP 통신에서 허가할 헤더들
package -

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;
import java.util.List;

@Configuration
public class CorsConfig {
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();

        config.setAllowCredentials(false);
        config.setAllowedOrigins(Arrays.asList("*"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
        config.setExposedHeaders(List.of("Authorization","Content-Type", "Accept"));
        config.setAllowedHeaders(List.of("Authorization","Content-Type", "Accept"));

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return source;
    }
}

🧑🏻‍💻 테스트 해보기

환경
1. Client  : React      localhost:3000
2. Server : AWS EC2  1.2.3.4:8080
3. Spring Boot v3.1.5

아마 잘 된다. 더 큰 문제는 다음 화에 이어진다.

기타

Postman은 CORS를 발생시키지 않으니, 꼭 실제 React나 브라우저에서 테스트해보길 권유한다.

나도 Postman에서는 정상 작동하는데, 브라우저로 가거나 React에서 요청하면 그때 CORS가 발생한다.

😃 다음화

[Spring] CORS 문제 해결하기!

profile
백엔드 개발자 전현준입니다.

0개의 댓글

관련 채용 정보