https://www.maeil-mail.kr/question/96
요약: 서로 리소스를 주고받는 두곳의 출처가 다를 때 cors오류가 발생하며, 이 문제는 서버에서 access-control-allow-origin 헤더의 설정을 통해서 해결이 가능하다.
CORS는 Cross Origin Resource Sharing
의 약자이다. 일반적으로 Origin은 웹 페이지를 호스팅하는 서버의 출처를 의미한다.
즉, cors는 출처가 다른 서버와 클라이언트가 리소스를 주고받을 때 접근 권한을 지정하는 것을 의미한다.
Origin은 프로토콜,호스트(도메인),포트로 구성되어 있다.
클라이언트와 서버간의 관계에서
CORS는 클라이언트의 origin과 서버의 origin이 다르고, 같은 경우에 대한 클라이언트가 서버에 접근을 할 수 있는지에 대한 정책을 부여하는 메커니즘이다.
클라이언트 웹사이트의 Origin: https://mywebsite.com
API 서버의 Origin: https://api.example.com
이런 경우에는 서로가 다른 도메인이자, origin을 가지고 있기 때문에 cors 정책이 어긋나기에, cors오류가 생길 것이다.
우리가 일반적으로 경험하는 클라이언트와 서버의 api연결을 할 때의 cors상황을 아래의 예시로 알아보자
Access to fetch at 'http://localhost:8080/api/data' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
이 경우 api를 연동시 발생하는 오류이다. 서로간의 도메인은 같아도 포트가 다르므로 서로의 origin이 다른 것이다.
React 개발 서버: http://localhost:3000
Spring 서버: http://localhost:8080
origin이 다르기에 cors오류가 발생하는 것이다.
과거에는 피해자의 브라우저에서 다른 애플리케이션으로 가짜 클라이언트 요청을 전송하는 공격인 csrf(cross-Site Request Forgecy)문제가 있었기 때문이다.
csrf는 브라우저의 사용자가 의도치 않게 공격자로 하여금, 다른 웹사이트나 api로 전송되어 공격을 당하게 되는 것이다.
이를 막기 위해서 같은 origin에서만의 리소스 교류만을 허용하였는데 이것이 SOP(Same Origin Police)이다.
그러나 현대의 어플리케이션에서 같은 origin에서의 소통만 있는 것이 아닌 다른 origin 에서의 소통은 너무 많다. 이 때문에 cors정책이 나와서, 다른 origin끼리의 소통을 할 수 있게 해주는 것이다.
일반적으로 브라우저가 요청 메시지에 origin 헤더와 응답메시지의 Access-Control-Allow-Origin 헤더를 비교해서 CORS를 위반 하는 지 확인 하는 방식이다.
이 경우는 method가 요청 (get,head,post)메서드이고, 수동으로 설정한 요청 헤더(Accept-Language,Content-Langauage,Content-Type, Range),Content-Type 헤더(application/x-www-form-urlencoded, multipart/form-data, text/plain)인 경우만 해당한다
이 때는 서버내에서 코드를 통해서 cors정책을 아래와 같이 제어할 수 있다.
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("https://aaaa.com/"); //// 필요한 도메인으로 설정하세요
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
configuration.setAllowCredentials(true);
configuration.setExposedHeaders(Arrays.asList("Authorization", "Authorization-refresh"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
출처: https://velog.io/@garcon/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-CORS%EC%99%80-credentials
이 경우는 본 요청을 보내기전에 OPTIONS 메서드를 통해서 해당 origin이 안전한 요청을 보낸건지 한번 확인 후에 보낸다
브라우저에서는 Access-Control-Request-Method
와 Access-Control-Request-Headers
헤더를 모두 담아서 보내야한다
또한 응답으로는 Access-Control-Allow-Methods
, Access-Control-Headers
를 보내며, Access-Control-Max-Age
를 통해서 preflight request의 추가 요청을 줄일 수 있다.
쿠키나 토큰과 같은 인증 정보를 포함한 요청일 때 발생하는 요청임.
Credential Request를 요청하는 경우에는 서버에서는 Access-Control-Allow-Credentials를 true로 설정해야 하며 Access-Control-Allow-Origin에 와일드카드를 사용하지 못한다.