ETC

[CORS] Cross Origin Resource Sharing

tubee 2017. 3. 3. 00:38

■ CORS - Cross Origin Resource Sharing


CORS란 개념에 대해 정리하겠습니다.


CORS란?

CORS란 Cross Origin Resource Sharing의 줄임말로, Cross-Site Http Request를 가능하게


하는 표준 규약입니다.


다른 도메인으로부터 리소스가 필요할 경우 cross-site http request가 필요합니다.


기존에는 XMLHttpRequest는 보안상의 이유로 자신과 동일한 도메인으로만 HTTP요청을 보내도록


제한하였습니다. 즉 cross-origin http 요청을 제한하였죠


하지만 지속적으로 웹 애플리케이션을 개선하고 쉽게 개발하기 위해서는 이러한 request가


꼭 필요했습니다. 그래서 XMLHttpRequest가 cross-domain을 요청할 수 있도록하는 방법이


필요하게 되었죠. 이러한 요청을 바탕으로 CORS가 탄생하였습니다.


CORS의 종류


크게 4종류로 나누어 볼 수 있습니다. 4가지 종류는 아래와 같습니다.

- Simple Request

- Preflight Request

- Credential Request

- Non-Credential Request


개념 및 예제 Request/Response를 통해 정리해보도록 할게요.


- Simple Request

먼저 기본적인 Simple Request입니다. 이는 다음 3가지를 만족해야 해요

1. GET, HEAD, POST 중 한 가지 방식을 사용

2. POST일 경우 Content-type이 아래 셋 중 하나를 만족

- application/x-www-form-urlencoded

- multipart/form-data

- text/plain

3. 커스텀 헤더를 전송하지 않아야 함


Simple Request는 매우 간단한 형태로 요청되고 응답됩니다. 


그 형태는 아래와 같습니다. (파란 블록이 Request / 노란 블록이 Response)


GET /resources/public-data/ HTTP/1.1

Host: bar.other

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1. 9.1b3pre) Gecko/20081130 Minefield/3.1b3pre

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

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

Connection: keep-alive

Referer: http://foo.example/examples/access-control/simpleXSInvocation.html

Origin: http://foo.example

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 00:23:53 GMT

Server: Apache/2.0.61 

Access-Control-Allow-Origin: *

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Transfer-Encoding: chunked

Content-Type: application/xml


위의 요청 및 응답에 대해 설명하겠습니다.


파란 블록의 HTTP Request는 foo.example로 부터 온 요청입니다.


노란 블록의 HTTP Response는 bar.other로 부터 온 응답입니다.


중간의 Access-Control-Allow-Origin: *이 보이시나요? 


이는 bar.other이 cross-site 방식 내 모든 도메인으로부터 접근이 가능하다는 뜻입니다.


만약 요청한 페이지인 foo.example만을 포함했다면 아마 아래와 같이 표기되었겠죠?

Access-Control-Allow-Origin: foo.example




- Preflight Request

두 번째는 Preflight Request입니다.


이름에서 볼 수 있는 것 처럼 Preflight(예비) 요청을 먼저 보내고 서버가 이에


응답이 가능한 지 확인합니다. 예비 요청은 OPTION메소드로 HTTP요청을 전송합니다.


이후 실제 Actual(본) 요청을 보냅니다.


그리고 서버가 이에 응답하며 통신하는 형태이죠.


Preflight Request는 위의 Simple Request에 해당하는 조건에 만족하면 안되요.


그렇기에 GET, HEAD, POST 이외 메소드를 사용하는 경우에만 사용 가능한 요청입니다


만약 POST 요청을 사용할 경우에는 Content Type이 위의 3가지 경우가 아니거나 


또는 커스텀 헤더를 사용할 경우에 사용할 수 있다는 점을 기억해야 합니다.


예비 요청과 예비 응답, 본 요청과 본 응답 총 4번의 형태로 구성되어 있습니다.


OPTIONS /resources/post-here/ HTTP/1.1

Host: bar.other

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre

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

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

Connection: keep-alive

Origin: http://foo.example

Access-Control-Request-Method: POST

Access-Control-Request-Headers: X-PINGOTHER

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 01:15:39 GMT

Server: Apache/2.0.61 (Unix)

Access-Control-Allow-Origin: http://foo.example

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Allow-Headers: X-PINGOTHER

Access-Control-Max-Age: 1728000

Vary: Accept-Encoding, Origin

Content-Encoding: gzip

Content-Length: 0

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Content-Type: text/plain


먼저 예비 요청 및 응답에 대해서 볼까요


위에 말한 것 처럼 OPTION 메소드를 이용하여 예비 요청을 보냈습니다.


Access-Control-Request-Method: POST는 이후 본 요청에서 POST 메소드가 


전달 될 것을 미리 알려주는 역할을 합니다.


Access-Control-Request-Headers: X-PINGOTHER는 본 요청에서 전달될 헤더 정보를


포함하고 있는데요. X-PINGOTHER이라는 커스텀 헤더가 전송될 예정입니다.


이후 이 예비 요청에 대한 응답이 위의 노란 블록처럼 전해집니다.


자세히 살펴봐야 할 것은 아래의 3줄입니다.

Access-Control-Allow-Origin: http://foo.example

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Allow-Headers: X-PINGOTHER


셋 모두 Access-Control-Allow-* 이렇게 시작합니다. 


당연히 허가된 정보를 뜻하는 것이지요. 


이후에는 위의 Simple Request와 같이 본 요청과 응답이 수행됩니다.




- Credential

세 번째는 HTTP Cookie와 HTTP Authentication 정보를 인식할 수 있게 해주는 요청입니다


요청 시 xhr.withCredentials = true를 지정하는 것이 가장 큰 특징입니다.


GET /resources/access-control-with-credentials/ HTTP/1.1

Host: bar.other

User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre

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

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

Connection: keep-alive

Referer: http://foo.example/examples/credential.html

Origin: http://foo.example

Cookie: pageAccess=2

HTTP/1.1 200 OK

Date: Mon, 01 Dec 2008 01:34:52 GMT

Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2

X-Powered-By: PHP/5.2.6

Access-Control-Allow-Origin: http://foo.example

Access-Control-Allow-Credentials: true

Cache-Control: no-cache

Pragma: no-cache

Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT

Vary: Accept-Encoding, Origin

Content-Encoding: gzip

Content-Length: 106

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Content-Type: text/plain


크게 다른 점은 없습니다. 중요하게 살펴볼 곳은 한군데입니다.


Access-Control-Allow-Credentials: true

만약 위의 설정이 false라면? 브라우저는 이 요청을 거부할 것입니다.


거부 할 때는 거부되었다는 어떠한 메시지도 전달하지 않아요. Response가 없습니다.



- Non-Credential

마지막 요청은 Non-Credential 요청입니다.


사실 withCredentials 플래그는 디폴트 값이 false입니다.


그러니 위의 Credential 요청에서와 같이 처리해주지 않는다면 모든 요청이 바로


Non-Credential에 해당된다고 볼 수 있습니다.




4가지의 CORS에 대해 정리해 보았습니다. 직접 테스트하고 실제 메시지를 보면 도움이 되겠죠?


과연 정리한 것처럼 요청과 응답이 올까요? 직접 확인해 볼 수 있는 사이트를 소개해드립니다.


http://arunranga.com/examples/access-control/


접속 후 테스트를 해볼 수 있어요. 개발자 도구 켜는건 당연한거겠죠?


직접 개념이해 후 확인해보면 완전히 이해하실겁니다.


그럼 포스팅을 마치겠습니다. 감사합니다