공통/Web & Network

[CORS] CORS 정리

반응형

Same-Origin Policy & Cross-Origin Policy


HTTP 요청에 대해서

  • HTML → 기본적으로 Cross-Origin 정책을 따름
    • link 태그에서 다른 origin의 css 등의 리소스에 접근하는 것이 가능하며, img 태그등에서 다른 리소스에 접근하는 것이 가능
  • XMLHttpRequest, Fetch APIscript 태그 내 → 기본적으로 Same-Origin 정책을 따름
    • 기본적으로 다른 Origin에 있는 리소스에 접근할 수 없다.


여기서 Origin이란?


같은 출처 (Origin)이란

  • URL 구성 요소 중 Scheme, Host, Port 이 동일한 경우 같은 Origin이라고 판단한다.

URL이 https://will.seungho.com:443 인경우를 예로 들면

이 세개가 모두 같으면 Same Origin라고 보면 된다. (하나라도 다른 경우 다른 출처)


다른 출처의 케이스에는 무엇이 있을까요?

보통 프론트엔드 개발자가 React와 같은 라이브러리를 사용해서 개발하는 경우 백엔드 서버와 별도의 프론트 서버가 존재한다.

프론트 개발을 할때, 로컬의 백엔드 서버에 연동하거나 개발 서버에 연결해서 API 연동을 하는데. 프론트 서버의 URL이 http://localhost:3000이고, 백엔드 서버가 http://localhost:8080에 띄워져 있다고 하자. (혹은 개발서버인 경우 https://potato.com

이때 프론트 서버와 백엔드 서버는 다른 출처 (Origin)으로써, Same-Origin Policy 정책을 어긋나기 때문에, 서버로부터 응답이 넘어올 때 브라우저에서 CORS Policy 오류를 발생시킨다.

사실 마지막 문장인 "서버로부터 응답이 넘어올 때 브라우저에서 CORS Policy 오류를 발생시킨다."가 중요한 말인데 포스트맨에서 API 테스트를 위해 서버로 API 요청할 때, CORS Policy가 안뜨는데, 프론트 개발할때는 CORS Policy가 뜨는 이유를 아시나요?


왜 포스트맨에서 서버로 요청시, CORS Policy 오류가 발생하지 않나요?

왜냐하면 CORS는 크롬 같은 브라우저에서 SOP 정책을 지켜서 다른 출처의 리소스 접근을 금지하기 때문이다. 즉, 다른 Origin일 경우 서버에서 CORS Policy 오류를 띄워주는게 아니라, 브라우저단에서 서버로부터의 응답을 막는것.


아니.. 왜 SOP같은 불편한 보안 정책을 두었나?


Same Origin Policy(동일 출처 정책)은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있다.

  • 하지만 외부 리소스 (백엔드 서버 or 구글과 같은)를 참고하는 것이 필요해짐에 따라, W3C에서 조금 더 안전하게 브라우저와 서버간에 교차 통신을 할 수 있도록 CORS 정책을 내놓았음.


그러면 이러한 CORS Policy 오류를 해결하는 방법에는 무엇이 있을까요?


  1. CORS 정책 사용
    1. 위에서 말한 CORS 정책을 이용한 방법으로, 서버에서 응답을 넘겨줄때 Access-Control-Allow-Origin 및 Access-Control-Allow-Methods Access-Control-Allow-Credential 등 헤더를 추가해서 응답을 넘겨주는 방법.
  1. 프록시 서버를 두는 방법
    • 보통 localhost에서 개발할 때, 서버에서 보안상 localhost를 허용된 Origin으로 포함하지 않음.
    • 이런 경우, 프론트와 백엔드 사이에 프록시 서버를 두는 방법으로 해결할 수 있으며, Webpack Dev Server 등의 라이브러리를 사용해서 프록시 설정을 하는 방법도 존재.


CORS는 어떻게 동작할까요?


CORS 동작에는 크게 Simple RequestPreflight Request 가 있다.


Simple Request


단순 요청은 서버에 API를 요청하고, 서버는 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보냄. 브라우저는 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단.


Simple request 조건

서버로 전달하는 요청(request)이 아래의 3가지 조건을 만족해야 서버로 전달하는 요청이 Simple Request으로 동작.

  • 요청 메서드(method)는 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 중 하나를 사용해야 한다.


Simple Request를 사용할 수 없는 경우가 많이 있는데, 예를 들어서 인증을 위해서 Authorization 헤더에 토큰을 포함해서 전달하는 경우, 혹은 Content-Type을 application/json 으로 전송하는 경우 Simple Request를 사용할 수 없다.

또는 PUT, DELETE 메소드를 사용하는 경우도 Simple Request를 사용할 수 없다.

→ 이런 경우에는 CORS는 아래의 Preflight Request 방식으로 동작한다.


Preflight Request


  • 브라우저가 진짜 요청을 보내기 전에 보내는 예비 요청을 Preflight라고 하며, HTTP 메소드 중 OPTIONS 메소드가 사용됨.
  • HTTP Method 중 OPTIONS 메소드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보냅니다. 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단함.


CORS를 해결하기 위한 Headers


Access-Control-Allow-Origin

Access-Control-Allow-Origin 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용함.

Access-Control-Allow-Origin: <https://potato.com>


Access-Control-Allow-Methods

브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Methods 헤더에 대한 응답 결과입니다. 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더임.

Access-Control-Request-Methods: GET, POST, PUT, DELETE


Access-Control-Expose-Headers

서버에서 응답 헤더에 Access-Control-Expose-Headers를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다.

Access-Control-Expose-Headers: Authorization


Access-Control-Max-Age

preflight 요청 결과를 캐시 할 수 있는 시간을 나타냄.

Access-Control-Max-Age: 60
  • 60초 동안 preflight 요청을 캐시하는 설정으로, 첫 요청 이후 60초 동안은 OPTIONS 메소드를 사용하는 예비 요청을 보내지 않는다.


Access-Control-Allow-Credentials: true

자바스크립트 요청에서 credentials include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다.

fetch('<http://localhost:3001/cors>', {
  method: 'PUT',
  credentials: 'include' // 요 credentials
}).then(function(response) {
}).catch(function(error) {
})
  • 자격 증명들은 쿠키, Authorization 헤더들 또는 TLS 클라이언트 인증서들을 포함함.


출처

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

https://ko.wikipedia.org/wiki/교차_출처_리소스_공유

https://vvshinevv.tistory.com/60

https://evan-moon.github.io/2020/05/21/about-cors/

반응형

'공통 > Web & Network' 카테고리의 다른 글

네트워크의 흐름 2단계  (0) 2021.08.05
네트워크의 흐름 1단계  (0) 2021.08.01