Cross-Origin-Resource-Sharing 의 줄임말로, 교차 출처 리소스 공유 라는 뜻이다.
사진 출처 : CORS의 기본 개념과 동작 방식(부제: Preflight 요청이란?)
(Origin)
이 다르면 발생하는 브라우저 정책cross-origin
은 다음 중 한가지라도 다른 경우를 말함. 이 셋 중 하나라도 다르면 CORS 가 발생한다.
http
/ https
두 프로토콜은 다르다.localhost
/ naver.com
두개는 다르다.8080
/ 3000
은 다르다.프로젝트 하면 Backend는 Java Spring
으로 개발하고 Frontend를 React
로 개발할 때
REST API 형태로 개발할 것이다.
HTTP 통신을 하게 되면 Spring의 톰캣은 localhost:8080
/ React : localhost:3000
으로 다르다.
이때 서버로 데이터를 요청해야 하는데, 이때 CORS가 발생할 가능성이 높다.
- Simple Request : 단순 요청
- Preflight Request : 예비 요청
- Credential Request : 인증된 요청
단순히 요청을 보내는 방법이다.
Client
가 요청을 보내면 Server
는 Access-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-Type
이 application/json
이기 때문에 Preflight로 처리 된다.
서버에 예비 요청을 보내는 것, Preflight
요청을 받아서 비교하고, 허가되지 않은 요청이면 CORS 발생
미리 이 예비 요청은 OPTIONS
방식으로 보낸다.
만약 CORS가 걸리는 요청인데 API 호출하면 불필요한 리소스를 낭비하기에 예비 요청을 통해서 불필요한 리소스를 줄이는 것이다.
인증정보를 포함한 요청, 보안을 강화하고 싶을 때 헤더에 인증 정보를 넣어 보내는 방식.
Access-Control-Allow-Credentials : true
를 추가한다.Access-Control-Allow-Origin
을 정확하게 설정한다. *
로 설정 X나의 경우에는 JWT 토큰을 담아 보안을 강화했다.
헤더에 Authorization
에 토큰을 담아 요청을 보낸다.
여기서는 간단하게 세팅할 수 있는 방법으로 살펴보겠다. 모든 도메인을 허가하는 방식이다.
본인에게 필요하게 변경하여 사용하면 되겠다.
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 : Reactlocalhost:3000
2. Server : AWS EC21.2.3.4:8080
3. Spring Boot v3.1.5
아마 잘 된다. 더 큰 문제는 다음 화에 이어진다.
기타
Postman은 CORS를 발생시키지 않으니, 꼭 실제 React나 브라우저에서 테스트해보길 권유한다.
나도 Postman에서는 정상 작동하는데, 브라우저로 가거나 React에서 요청하면 그때 CORS가 발생한다.