wrkbrs

[HTTP] CORS 본문

HTTP

[HTTP] CORS

zcarc 2019. 12. 21. 19:28

개요

HTTP 요청은 기본적으로 Cross-Site HTTP Requests가 가능합니다. 다시 말하면, <img> 태그로 다른 도메인의 이미지 파일을 가져오거나, <link> 태그로 다른 도메인의 CSS를 가져오거나, <script> 태그로 다른 도메인의 JavaScript 라이브러리를 가져오는 것이 모두 가능합니다. 하지만 <script></script>로 둘러싸여 있는 스크립트에서 생성된 Cross-Site HTTP Requests는 Same Origin Policy를 적용 받기 때문에 Cross-Site HTTP Requests가 불가능합니다. 즉, 프로토콜호스트명포트가 같아야만 요청이 가능합니다.

AJAX가 널리 사용되면서 <script></script>로 둘러싸여 있는 스크립트에서 생성되는 XMLHttpRequest에 대해서도 Cross-Site HTTP Requests가 가능해야 한다는 요구가 늘어나자 W3C에서 CORS라는 이름의 권고안이 나오게 되었습니다.

CORS 요청의 종류

CORS 요청은 Simple/Preflight, Credential/Non-Credential의 조합으로 4가지가 존재합니다. 브라우저가 요청 내용을 분석하여 4가지 방식 중 해당하는 방식으로 서버에 요청을 날리므로, 프로그래머가 목적에 맞는 방식을 선택하고 그 조건에 맞게 코딩해야 합니다.

Simple Request

아래의 3가지 조건을 모두 만족하면 Simple Request

  • GET, HEAD, POST 중의 한 가지 방식을 사용해야함.
  • POST 방식일 경우 Content-type이 아래 셋 중의 하나여야함.
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • 커스텀 헤더를 전송하지 말아야함.

Simple Request는 서버에 1번 요청하고, 서버도 1번 회신하는 것으로 처리가 종료됩니다.

 

Preflight Request

Simple Request 조건에 해당하지 않으면 브라우저는 Preflight Request 방식으로 요청합니다.따라서, Preflight Request는 GET, HEAD, POST 외의 다른 방식으로도 요청을 보낼 수 있고, application/xml 처럼 다른 Content-type으로 요청을 보낼 수도 있으며, 커스텀 헤더도 사용할 수 있습니다.

이름에서 짐작할 수 있듯, Preflight Request는 예비 요청과 본 요청으로 나뉘어 전송됩니다. 먼저 서버에 예비 요청(Preflight Request)를 보내고 서버는 예비 요청에 대해 응답하고, 그 다음에 본 요청(Actual Request)을 서버에 보내고, 서버도 본 요청에 응답합니다.

하지만, 예비 요청과 본 요청에 대한 서버단의 응답을 프로그래머가 프로그램 내에서 구분하여 처리하는 것은 아닙니다. 프로그래머가 Access-Control- 계열의 Response Header만 적절히 정해주면, OPTIONS 요청으로 오는 예비 요청과 GET, POST, HEAD, PUT, DELETE 등으로 오는 본 요청의 처리는 서버가 알아서 처리합니다.

아래는 Preflight Requests로 오가는 HEADER를 보여줍니다.

 

Request with Credential

HTTP Cookie와 HTTP Authentication 정보를 인식할 수 있게 해주는 요청

요청 시 xhr.withCredentials = true를 지정해서 Credential 요청을 보낼 수 있고, 서버는 Response Header에 반드시 Access-Control-Allow-Credentials: true를 포함해야 하고, Access-Control-Allow-Origin 헤더의 값에는 *가 오면 안되고 http://foo.origin과 같은 구체적인 도메인이 와야 합니다. 만약 Credentials 옵션은 true로 줬는데 Access-Control-Allow-Origin의 값을 *로 주면 에러가 발생합니다.

Request without Credential

CORS 요청은 기본적으로 Non-Credential 요청이므로, xhr.withCredentials = true를 지정하지 않으면 Non-Credential 요청입니다.

CORS 관련 HTTP Response Headers

서버에서 CORS 요청을 처리할 때 지정하는 헤더

Access-Control-Allow-Origin

Access-Control-Allow-Origin 헤더의 값으로 지정된 도메인으로부터의 요청만 서버의 리소스에 접근할 수 있게 합니다.

Response Header

 

<origin>에는 요청 도메인의 URI를 지정합니다. 모든 도메인으로부터의 서버 리소스 접근을 허용하려면 *를 지정합니다. Request with Credential의 경우에는 *를 사용할 수 없습니다. 또한 보통 Access-Control-Allow-Origin 옵션은 1개의 도메인만 작성할 수 있게 되어 있습니다. 만약 1개 이상의 도메인을 적으면 에러를 발생합니다. (해결방안은 스크립트로..)

Access-Control-Expose-Headers

기본적으로 브라우저에게 노출이 되지 않지만, 브라우저 측에서 접근할 수 있게 허용해주는 헤더를 지정합니다.

기본적으로 브라우저에게 노출이 되는 HTTP Response Header는 아래의 6가지 밖에 없습니다.

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

다음과 같이 Access-Control-Expose-Headers를 Response Header에 지정하여 회신하면 브라우저 측에서 커스텀 헤더를 포함하여, 기본적으로는 접근할 수 없었던 Content-Length 헤더 정보도 알 수 있게 됩니다.

Response Header

 

Access-Control-Max-Age

 Preflight Request의 결과가 캐쉬에 얼마나 오래동안 남아있는지를 나타냅니다.

Response Header

 

Access-Control-Allow-Credentials

Request with Credential 방식이 사용될 수 있는지를 지정합니다.

Response Header

 

 

Simple Request에 withCredentials = true가 지정되어 있는데, Response Header에 Access-Control-Allow-Credentials: true가 명시되어 있지 않다면, 그 Response는 브라우저에 의해 무시됩니다. 예비 요청에 대한 응답에 Access-Control-Allow-Credentials: false를 포함하면, 본 요청은 Request with Credential을 보낼 수 없습니다.

Access-Control-Allow-Methods

예비 요청에 대한 Response Header에 사용되며, 서버의 리소스에 접근할 수 있는 HTTP Method 방식을 지정합니다.

Response Header

 

GET, POST, DELETE, PATCH 등등이 존재합니다.

Access-Control-Allow-Headers

 예비 요청에 대한 Response Header에 사용되며, 본 요청에서 사용할 수 있는 HTTP Header를 지정합니다.

Response Header

 

Content-Type,Accept-Encoding, X-CSRF-Token, Authorization 등이 있습니다.

 

CORS 관련 HTTP Request Headers

클라이언트가 서버에 CORS 요청을 보낼 때 사용하는 헤더로, 브라우저가 자동으로 지정하며, XMLHttpRequest를 사용하는 프로그래머가 직접 지정해 줄 필요가 없습니다.

Origin

Cross-site 요청을 날리는 요청 도메인 URI을 나타내며, access control이 적용되는 모든 요청에 Origin 헤더는 반드시 포함됩니다.

Request Header

 

<origin>은 공백일 수도 있는데, 소스가 data URL일 경우에 유용합니다.<origin>은 서버 이름(포트 포함)만 포함되며 경로 정보는 포함되지 않습니다.

Access-Control-Request-Method

예비 요청을 보낼 때 포함되어, 본 요청에서 어떤 HTTP Method를 사용할 지 서버에게 알려줍니다.

Request Header

 

<method>는 POST, GET, DELETE 등이 포함될 수 있습니다.

Access-Control-Request-Headers

예비 요청을 보낼 때 포함되어, 본 요청에서 어떤 HTTP Header를 사용할 지 서버에게 알려준다.

Request Header

 

Authorization, Content-type 등이 있습니다.

결론

  • CORS를 쓰면 AJAX로도 Same Origin Policy의 제약을 넘어 다른 도메인의 자원을 사용할 수 있음
  • CORS를 사용하려면 클라이언트에서 Access-Control-** 류의 HTTP Header를 서버에 보내야 하고, 서버도 Access-Control-** 류의 HTTP Header를 클라이언트에 회신하게 되어 있어야 함.



출처: https://brownbears.tistory.com/336 [불곰]