시작하며
프론트 개발을 하다 보면 아래와 같은 에러를 많이 보게 된다.
(종류 별로 준비해 본…)
그래서 찾아 본 CORS!
동일 출처 정책 뭔가?
동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식이다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여준다
보안 이슈로 인해 이런 정책이 생겼다고 한다.
사실 하나의 프로젝트 안에서 모든 호출이 이루어진다면 이런 문제도 없겠지만 API를 이용한 외부 접근이 많아 지고 있어 불편한 정책이 되어 버렸다. 그래서 다시 정해진 정책이 CORS!
서버단에서 동일 출처 정책에 대한 처리가 되어 있지 않다면 이것을 우회 하는 방법이 있긴 하다.
- 크롬브라우저의 경우
- 강제 출처 변경
- document.domain = “”;
- 스크립트 호출시 jsonp 사용.
하지만 port만 다를 경우는 위의 방법으로는 되지 않고, 여러 다른 문제가 생길 수도 있어서 서버에서 정식으로 지원해 주는 것이 제일 좋다.
CORS란?
CORS(Cross-Origin Resource Sharing, 교차 출처 자원 공유)는 웹 페이지 상의 제한된 자원을 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이며, 브라우저의 구현 스펙에 포함되는 정책이기 때문에, 브라우저를 통하지 않고 서버 간 통신을 할 때는 이 정책이 적용되지 않는다.
CORS 동작원리
Preflight Request
제일 일반적인 형태로 client에서 브라우저 에게 명령을 내리면 브라우저는 서버로 예비 요청을 보내고 server에서 Header에 정보를 담아 보내 준다.
브라우저는 이 정보와 예비 정보를 비교 한 후, 이 정보가 안전하다고 판단이 되면 다시 본 요청을 보내 실질적인 응답데이터를 client로 넘겨 주게 된다.
Simple Request
Preflight Request 에서 예비 요청 단계를 뺀 것으로 특정 조건을 만족하는 경우에만 사용 가능하다.
- 요청의 메소드는 GET, HEAD, POST 중 하나여야 한다.
- Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안된다.
- 만약 Content-Type를 사용하는 경우에는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용된다.
하지만 요청 값에 Authorization 값이 포함 되지 않아 인증을 요구하는 사이트에는 적합하지 않다.
Credentialed Request
다른 출처 간 통신에서 좀 더 보안을 강화하고 싶을 때 사용하는 방법이다. request에 opiton값을 주는 것인데, fetch를 할 때 옵션에 credentials: ‘include’를 주면 다음 두 가지 조건을 추가함으로써 정책 위반 여부를 확인하는 규칙이 엄격해진다.
- credentialed request 에 응답할 때 서버는 Access-Control-Allow-Origin 헤더 “*” 와일드카드를 사용하는 대신에 반드시 에 값을 지정해야 한다.
- Access-Control-Allow-Credentials: true 로 응답하지 않으면, 응답은 무시되고 웹 컨텐츠는 제공되지 않는다.
어떻게 해야 할까?
Springboot
Configuration설정
//springboot 서버단에 설정해 주기.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/test/**")
.allowedOrigins("http://maan.com:1003")
;
}
}
//여러개 설정도 가능
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080", "http://localhost:8081");
}
}
Annotation이용
//class 적용
@RestController
@RequestMapping("/test")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class MainController {
@RequestMapping("/helloworld")
public String hello() {
return "Hello World";
}
}
//Method 적용
@RequestMapping("/helloworld")
@CrossOrigin(origins = "*")
public String hello() {
return "Hello World";
}
리액트
proxy 사용하여 리액트에서 CORS 처리를 해 보았다.
http-proxy-middleware를 먼저 설치 한 후 setupProxy파일을 아래와 같이 생성해 주었다.
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/test',
proxy({
target: 'http://localhost:8080',
changeOrigin: true,
})
);
}; // 구버전
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/test',
createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
})
);
};//신버전
//http-proxy-middleware 설치 : npm install http-proxy-middleware --save
참고한 사이트
http://jag212.github.io/ChromeCrossDomain/
https://evan-moon.github.io/2020/05/21/about-cors/
https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
https://ko.wikipedia.org/wiki/교차_출처_리소스_공유
https://brunch.co.kr/@adrenalinee31/1