토이 프로젝트를 개발하다가 자주 이 이슈를 마주해서 이참에 개념 정리를 해볼겸 글을 작성하게 되었다.
* CORS
CORS 란 다른 출처(Origin) 간의 Resource 에 대한 접근, 공유 권한을 처리하는 보안 정책이다.
* Origin ?
출처(Origin) 이란 것은 URL 의 구성요소에서 protocol, host, port 를 의미하는데,
URL 은 보통 아래 같이 구성된다.
출처(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 의 논리를 수행하는 부분은 서버가 아니라, 브라우저이다.
CORS 정책을 위반했든 안했든 일단 클라이언트에서 request 를 보내고, 이에 대한 response 를 서버에서 보내준다
그리고 나서 이것이 CORS 위반 인지 아닌지를 브라우저에서 판별하여 처리한다.
CORS 가 동작할때, 3가지 경우의 수가 있다.
1. Preflight Request
Preflight Request 를 단순하게 말하면, 본 요청을 보내기 전에 보내는 예비 요청을 Preflight Request 라 한다.
원래 보내고자 했던 요청을 보내기 전에 서버로 한번 예비용 요청을 보내봐서 안전성 여부를 판별하기 위해 사용된다.
Preflight Request 를 보내기 위해서는 HTTP 의 OPTION 메소드를 사용해서 보내야한다.
2. Simple Request
이 요청방식은 예비 요청을 보내지 않고 그냥 바로 본 요청을 보내는 방식이다.
대략 아래와 같은 과정을 거치면서 수행된다.
이 단순 요청 방식은 아래의 세가지 조건을 만족할때만 사용이 가능하다
-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://developer.mozilla.org/ko/docs/Web/HTTP/CORS
https://jeonghwan-kim.github.io/series/2020/01/02/frontend-dev-env-webpack-intermediate.html
'JS' 카테고리의 다른 글
CSP (Content Security Policy) 란? (0) | 2020.08.30 |
---|---|
#33 가지 Javascript 필수 개념 - 5. Equals (0) | 2020.08.22 |
Axios 와 Fetch (0) | 2020.08.06 |
#33가지 Javascript 필수 개념 - 4. Type Coercion (0) | 2020.08.02 |
#33가지 Javascript 필수 개념 - 3. Value Types, Reference Types (0) | 2020.07.29 |