JS

CORS (Cross Origin Resource Sharing)

728x90

토이 프로젝트를 개발하다가 자주 이 이슈를 마주해서 이참에 개념 정리를 해볼겸 글을 작성하게 되었다.

 

 

 

* CORS

CORS 란 다른 출처(Origin) 간의 Resource 에 대한 접근, 공유 권한을 처리하는 보안 정책이다.

 

 

* Origin ?

출처(Origin) 이란 것은 URL 의 구성요소에서 protocol, host, port 를 의미하는데,

 

URL 은 보통 아래 같이 구성된다.

출처 : https://cognitiveseo.com/blog/23628/url-structure/

 

출처(Origin) 이 동일한지 다른지는 앞서 언급한 세가지 요소 protocol, host(위 그림에서 domain), port number 가 같은지 다른지를 판별해서 결정된다.

 

port number 의 경우 http 는 기본 값이 80, https 는 기본 값이 443 이다. 

보통의 사이트들은 포트번호를 입력하고 접속하지 않는다. 

생략해서 기본 포트를 쓰는 것이 일반적이기 때문이다.

 

아래의 표는 기본 URL 이 https://sdy-study.tistory.com 이라 할때,

이 기본 URL 과 동일한 출처인지 아닌지 판별한것을 나타낸 표이다.

URL 동일성 여부 이유
https://sdy-study.tistory.com/53 o protocol, domain, port 가 같음
https://sdy-study.tistory.com/53?query=aa o protocol, domain, port 가 같음
http://sdy-study.tistory.com/ x protocol 이 다름
https://a.tistory.com x domain 이 다름
https://sdy-study.tistory.com:4000 ? port 번호가 다름

 

마지막만 물음표인 이유는 브라우저에 따라서 해석하는게 달라지는 경우가 있기 때문이다.

(IE 의 경우 포트 번호를 무시하고 해석한다고 함)

 

 

 

* CORS 의 동작 방식

CORS 의 논리를 수행하는 부분은 서버가 아니라, 브라우저이다.

출처 : https://evan-moon.github.io/2020/05/21/about-cors/#cors%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EB%82%B4%EC%9A%A9

 

CORS 정책을 위반했든 안했든 일단 클라이언트에서 request 를 보내고, 이에 대한 response 를 서버에서 보내준다

그리고 나서 이것이 CORS 위반 인지 아닌지를 브라우저에서 판별하여 처리한다.

 

CORS 가 동작할때, 3가지 경우의 수가 있다.

 

1. Preflight Request

Preflight Request 를 단순하게 말하면, 본 요청을 보내기 전에 보내는 예비 요청을 Preflight Request 라 한다.

원래 보내고자 했던 요청을 보내기 전에 서버로 한번 예비용 요청을 보내봐서 안전성 여부를 판별하기 위해 사용된다.

Preflight Request 를 보내기 위해서는 HTTP 의 OPTION 메소드를 사용해서 보내야한다.

 

출처 : https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

 

2. Simple Request

이 요청방식은 예비 요청을 보내지 않고 그냥 바로 본 요청을 보내는 방식이다.

대략 아래와 같은 과정을 거치면서 수행된다.

출처 : https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

 

이 단순 요청 방식은 아래의 세가지 조건을 만족할때만 사용이 가능하다

 

-1). HTTP Method 중 GET, POST, HEAD 만 사용이 가능하다.

-2). Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width 를 제외한 헤더를 사용할수 없다.

-3). Content-Type 를 사용하는 경우, application/x-www-form-urlencoded, multipart/form-data, text/plain 만 사용할 수 있다.

 

제약사항이 많기 때문에 잘 사용되지는 않는 것 같다. 

 

 

3. Credentialed Request 

보안에 좀 더 신경을 쓰고 싶은 경우 사용되는 방식이라고 한다.

보통 XMLHttpRequest 객체나, fetch 를 사용하는 경우 옵션 값을 따로 지정하지 않으면, 

쿠키 정보, 인증 관련 정보 등을 요청 값에 담지 않는다. 

정보를 담은채로 요청을 하고 싶을때, credentials 값을 지정해주는데,

 

credentials 로 설정할 수 있는 값은 아래와 같이 3가지로 구성된다.

 

-1). same-origin (기본값) : 같은 출처(origin) 간에만 정보를 담을 수 있다.

-2). include : 모든 요청에 인증 정보를 담을 수 있다.

-3). exclude : 모든 요청에 인증 정보를 담을 수 없다.

 

 

* CORS 문제에 대한 해결책

1. Access-Control-Allow-Origin 설정

백엔드 프레임워크에 Access-Control-Allow-Origin 값을 설정해서 어떤 출처에서 리소스 공유를 허용해줄것인지 설정할 수 있다, 

보통은 * 값을 써서 모든 출처에 대해 허용하는 것 보다는 직접 URL 을 지정해서 설정하는 것이 일반적이다.

모든 출처에 허용하면 보안상 문제가 생길 수 있다. (CSRF, XSS 등)

 

Spring 의 경우 

@CrossOrigin annotation 을 사용해서 처리 할 수 있다.

(참조 : https://spring.io/blog/2015/06/08/cors-support-in-spring-framework)

 

Express 의 경우 

res.header("Access-Control-Allow-Origin", "*"); 같이 설정할수도 있으며, 

미들웨어를 사용해서 처리할수 있기도 하다.

(참고 : https://github.com/expressjs/cors)

 

2. Webpack Dev Server 설정

보통 프론트엔드 개발시에 CORS 문제가 발생할때, webpack dev server 를 사용해서 해결한다고 한다.

 

이 케이스는 webpack-dev-server 를 통해 프록시 기능을 넣어서 우회를 하는 방향으로 해결한다고 한다.

예를 들면 다음과 같이 코드를 작성하면,

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://api.evan.com',
        changeOrigin: true,
        pathRewrite: { '^/api''' },
      },
    }
  }
}
cs

 

 

로컬 환경에서 localhost:4000/api 에 접속했을 때, 주소를 https://api.evan.com 으로 요청을 프록싱 해준다.

프록싱을 사용해서 마치 CORS 를 지킨 것처럼 바꿔서 보내는 방법인것.

 

webpack-dev-server 말고도, 

http-proxy-middleware 를 사용해서 처리하는 것도 가능하다

 

(참고 : https://www.npmjs.com/package/http-proxy-middleware)

 

 

 

- Reference

https://evan-moon.github.io/2020/05/21/about-cors/#cors%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EB%82%B4%EC%9A%A9

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

https://jeonghwan-kim.github.io/series/2020/01/02/frontend-dev-env-webpack-intermediate.html

 

 

728x90