개발관련/프론트엔드 지식

CORS에 대한 모든 것

개발자 Dane 2023. 4. 4. 21:05
반응형

CORS

SOP ( SAME ORIGIN POILICY )

동일 출처에 대한 요청에 관해서만 요청을 허락하는 보안 방식

동일 출처란?

프로토콜 / HOST / PORT 가 모두 동일해야 같은 출처로 처리 한다.

Cross Origin

동일 출처가 아니라는 것을 의미한다.

CORS(Cross Origin Resource Sharing)

Cross Origin Resource Sharing

다른 출처에 있는 리소스를 요청를 가능하게 제어하는 방법

단순 요청(Simple requests)

아래의 조건을 모두 만족하면 preflight 요청을 발생시키지 않는다.

Simple requests 용어는 MDN에서 임의로 사용.

 

다음 중 하나의 메소드

  • [GET]
  • [HEAD]
  • [POST]

헤더

유저 에이전트가 자동으로 설정 한 헤더

  • [Connection]
  • [User-Agent]

그외 헤더

  • [Accept]
  • [Accept-Language]
  • [Content-Language]
  • [Content-Type]

[Content-Type]헤더는 다음의 값들만 허용됩니다.

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Simple requests 요청시 Cors 동작 시나리오

https://foo.example 에서 https://bar.other 도메인에 요청시

const xhr = new XMLHttpRequest(); 
const url = 'https://bar.other/resources/public-data/'; 
xhr.open('GET', url); 
xhr.onreadystatechange = someHandler; 
xhr.send();
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

 

요청 헤더의 [Origin]을 보면, https://foo.example로부터 요청이 왔다는 것을 알 수 있습니다.

HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT 
Server: Apache/2 
Access-Control-Allow-Origin: * 
Keep-Alive: timeout=2, max=100 
Connection: Keep-Alive 
Transfer-Encoding: chunked 
Content-Type: application/xml […XML Data…]

 

서버는 이에 대한 응답으로 [Access-Control-Allow-Origin] 헤더를 다시 전송

가장 간단한 접근 제어 방법은 [Origin]헤더와 [Access-Control-Allow-Origin]을 사용

 

이 경우 서버는 Access-Control-Allow-Origin: *, 으로 응답

* 이는 모든 도메인에서 접근할 수 있음을 의미

 

오직 https://foo.example 의 요청만 리소스에 대한 접근을 허용하려는 경우

Access-Control-Allow-Origin: https://foo.example 으로 응답

 


Preflight

  1. OPTIONS 메서드를 통해 미리 요청을 보내 다른 도메인의 리소스에 요청이 가능한 지 확인 작업
    • 브라우저 자동 동작
  2. 요청이 가능하다면 실체 요청을 보냄.
    • 불가능 할 경우 403 에러

requests 요청시 Cors 동작 시나리오

const xhr = new XMLHttpRequest(); 
xhr.open('POST', 'https://bar.other/resources/post-here/'); 
xhr.setRequestHeader('Ping-Other', 'pingpong'); 
xhr.setRequestHeader('Content-Type', 'application/xml'); 
xhr.onreadystatechange = handler; 
xhr.send('<person><name>Arun</name></person>');

Preflight request

  • Origin : 요청 출처
  • Access-Control-Request-Method : 실제 요청의 메소드
  • Access-Control-Request-Headers : 실제 요청의 추가 헤더

Preflight response

  • Access-Control-Allow-Origin : 서버 측 허가 출처
  • Access-Control-Allow-Method : 서버 측 허가 메소드
  • Access-Control-Allow-Headers : 서버 측 허가 헤더
  • Access-Control-Max-Age : Preflight 응답 캐시 기간

Preflight request/response

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive

Prefilght request에 실제로 요청할 request 정보를 헤더에 포함해서 전송합니다.

  • Access-Control-Request-Method: POST
  • Access-Control-Request-Headers: X-PINGOTHER, Content-Type

서버는 사전에 CORS 허용된 옵션response 헤더에 포함해서 전송합니다.

  • Access-Control-Allow-Origin: http://foo.example
  • Access-Control-Allow-Methods: POST, GET, OPTIONS
  • Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
  • Access-Control-Max-Age: 86400

Real request/response

POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: https://foo.example
Pragma: no-cache
Cache-Control: no-cache

<person><name>Arun</name></person>


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

서버는 Access-Control-Allow-Methods 로 응답하고 POSTGET 이 리소스를 쿼리하는데 유용한 메서드라고 가르쳐줍니다. 이 헤더는 [Allow] 응답 헤더와 유사하지만, 접근 제어 컨텍스트 내에서 엄격하게 사용됩니다.

 

또한 Access-Control-Allow-Headers 의 값을 "X-PINGOTHER, Content-Type" 으로 전송하여 실제 요청에 헤더를 사용할 수 있음을 확인합니다. Access-Control-Allow-Methods와 마찬가지로 Access-Control-Allow-Headers 는 쉼표로 구분된 허용 가능한 헤더 목록입니다.

 

마지막으로[Access-Control-Max-Age (en-US)]는 다른 preflight request를 보내지 않고, preflight request에 대한 응답을 캐시할 수 있는 시간(초)을 제공합니다. 위의 코드는 86400 초(24시간) 입니다. 각 브라우저의 최대 캐싱 시간 (en-US)은 Access-Control-Max-Age 가 클수록 우선순위가 높습니다.

 

반응형