프로토콜, 도메인, 포트번호가 다른 외부 사이트에 데이터 요청을 했을 때,
보안상의 이유로 브라우저에서 HTTP 요청을 제한하는 것
Protocol - http !== https
Domain - domain.com !== other-domain.com
Port - 8080 !== 3000
👉 이 세가지중 하나라도 다른 경우 cross-origin
라 부른다.
ref: https://beomy.github.io/tech/browser/cors/
모든 곳에서 데이터를 요청할 수 있게 되면 다른 사이트를 흉내내어
기존 사이트와 동일하게 로그인을 하게 만들고, 로그인했던 세션을 탈취하여
악의적으로 정보를 추출하거나 다른 사람의 정보를 입력하는 등 ( XSS, XSRF )
공격을 할 수 있기 때문에 서버에서 동의를 한 경우에만 요청을 수락하고
동의하지 않으면 브라우저에서 거절한다.
출처 ( Origin )을 살펴보기 위해서 URL 구조를 먼저 살펴봐야 한다.
ref: https://beomy.github.io/tech/browser/cors/
Simple requests
Content-type
이 다음과 같은 경우preflight
Origin
헤더에 현재 요청하는 origin과, Access-Control-Request-Method
헤더에 요청하는 HTTP method와 Access-Control-Request-Headers
요청 시 사용할 헤더를 OPTIONS
메서드로 서버에 요청한다. ( 이때 내용물은 없고 헤더만 전송 )preflight?
Simple requests가 아닌 cross-origin요청은 모두 preflight요청을 하게 되는데,
실제 요청을 보내는 것이 안전한지 확인하기 위해 먼저 OPTIONS 메서드를 사용하여
cross-origin HTTP 요청을 보내는것
요청 헤더들은 별도로 명시해 주지 않아도 브라우저에서 OPTIONS
요청에 추가한다.
🔸 Origin: <origin>
Origin
헤더는 요청하는 대상의 출처를 나타낸다. API를 호출하는 페이지의 출처 값이 저장된다.
🔸 Access-Control-Request-Method: <method>
Access-Control-Request-Method
헤더는 실제 요청이 어떤 HTTP 메서드를 사용하는지 서버에 알려주기 위해 사용된다.
🔸 Access-Control-Request-Headers: <field-name[, <field-name>]
Access-Control-Request-Headers
헤더는 브라우저에서 보내는 커스텀 헤더 이름을 서버에 알려주기 위해 사용된다.
🔸 Access-Control-Allow-Origin: <origin>|*
Access-Control-Allow-Origin
헤더에 작성된 출처만 브라우저가 접근할 수 있도록 허용한다.
사용 방법
아래와 같이 응답 헤더가 작성되었다면 https://github.com/kisn3089
페이지에서 브라우저는 서버 응답으로 온 리소스를 접근할 수 있다.
Access-Control-Allow-Origin: https://github.com/kisn3089
아래와 같이 *
이 작성되었다면, 브라우저는 출처에 상관없이 모든 리소스에 접근할 수 있다.
Access-Control-Allow-Origin: *
🔸 Access-Control-Allow-Methods
브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Allow-Methods
헤더에 대한 응답 결과로, 리소스 접근을 허용하는 HTTP 메서드를 지정해주는 헤더이다.
사용 방법
Access-Control-Allow-Methods
헤더에 GET
, PUT
, POST
, DELETE
등의 HTTP 메서드를 ,
로 구분하여 넘겨준다.
Access-Control-Allow-Methods: GET, PUT
🔸 Access-Control-Expose-Headers: <header-name>[, <header-name>]*
서버에서 응답 헤더에 Access-Control-Expose-Headers
를 추가해 줘야 브라우저의 자바스크립트에서 헤더에 접근할 수 있다.
사용 방법
아래와 같이 ,
로 구분하여 여러 개의 헤더를 넣을 수 있다.
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
🔸 Access-Control-Allow-Headers: <header-name>[, <header-name>]*
브라우저에서 보내는 요청 헤더에 포함된 Access-Control-Request-Headers
헤더에 대한 응답 결과이다.
사용 방법
자바스크립트에서 커스텀 헤더를 서버에 전달하면, OPTIONS
요청 헤더의 Access-Control-Request-Headers
헤더에 커스텀 헤더 이름이 추가된다. 서버에서는 Access-Control-Request-Headers
에 작성된 값을 보고 Access-Control-Allow-Headers
응답 헤더에 커스텀 헤더 이름을 명시해 주어야 한다.
Access-Control-Expose-Headers: X-Custom-Request
🔸 Access-Control-Max-Age: <delta-seconds>
preflight 요청 결과를 캐시 할 수 있는 시간을 나타낸다.
사용 방법
아래와 같이 초 단위로 캐시 시간을 설정한다.
Access-Control-Max-Age: 60
위의 코드는 60초 동안 preflight 요청을 캐시 하는 코드이다. 60초 동안 OPTIONS
메서드를 사용하는 예비 요청을 보내지 않는다.
🔸 Access-Control-Allow-Credentials: true
자바스크립트 요청에서 credentials
가 include
일 때 요청에 대한 응답을 할 수 있는지를 나타낸다. false
로 설정해 주고 싶을 경우에는 헤더를 생략하면 된다.
사용 방법
Access-Control-Allow-Credentials: true
프론트엔드와 백엔드 사이에 프록시 서버를 두는 방법으로 CORS를 해결할 수도 있다. 개발 환경에서 CORS를 해결해야 한다면, Webpack Dev Server 등의 라이브러리를 사용해서 프록시 설정을 하는 방법도 있다.