4 minute read

교차 출처 리소스 공유(CORS)

CORS in MDN

단순 요청(Simple Requests)

일부요청은 CORS preflight를 트리거하지 않습니다. simple requests 는 다음 조건을 모두 충족하는 요청입니다.

다음 중 하나의 메서드

  • GET
  • HEAD
  • POST

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

(예를들어, Connection, User-Agent (en-US), Fetch 명세에서 “forbidden header name”으로 정의한 헤더)외에, 수동으로 설정할 수 있는 헤더는 오직 Fetch 명세에서 “CORS-safelisted request-header”로 정의한 헤더 뿐입니다.)

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

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

요청에 ReadableStream 객체가 사용되지 않습니다.

클라이언트와 서버간에 간단한 통신을 하고, CORS 헤더를 사용하여 권한을 처리합니다.
CORS diagram

위의 경우 요청과 응답을 살펴봅시다.

request:
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

response:
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: https://foo.example 이 응답 헤더에 포함되어있다면, https://foo.example 이외의 도메인은 cross-site 방식으로 리소스에 접근할 수 없습니다.

리소스에 대한 접근을 허용하려면, Access-Control-Allow-Origin 헤더에는 요청의 Origin 헤더에서 전송된 값이 포함되어야 합니다.

프리플라이트 요청

프리플라이트 요청은 위의 단순 요청과 달리, 먼저 OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인합니다. Cross-site 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이렇게 미리 전송(preflight)합니다.

CORS preflight

Access-Control-Request-Method 헤더는 preflight request의 일부로, 실제 요청을 전송할 때 POST 메서드로 전송된다는 것을 알려줍니다. Access-Control-Request-Headers 헤더는 실제 요청을 전송 할 때 X-PINGOTHER 와 Content-Type 사용자 정의 헤더와 함께 전송된다는 것을 서버에 알려줍니다. 이제 서버는 이러한 상황에서 요청을 수락할지 결정할 수 있습니다.

Preflighted request와 리다이렉트

모든 브라우저가 preflighted request 후 리다이렉트를 지원하지는 않습니다. preflighted request 후 리다이렉트가 발생하면 일부 브라우저는 다음과 같은 오류 메세지를 띄웁니다.

  • 요청이 ‘https://example.com/foo’로 리다이렉트 되었으며, preflight가 필요한 cross-origin 요청은 허용되지 않습니다.

  • 요청에 preflight가 필요합니다. preflight는 cross-origin 리다이렉트를 허용하지 않습니다.

CORS 프로토콜은 본래 그 동작(리다이렉트)이 필요했지만, 이후 더 이상 필요하지 않도록 변경되었습니다. 그러나 모든 브라우저가 변경 사항을 구현하지는 않았기 때문에, 본래의 필요한 동작은 여전히 나타납니다.

브라우저가 명세를 따라잡을 때까지 다음 중 하나 혹은 둘 다를 수행하여 이 제한을 해결할 수 있습니다.

  • preflight redirect를 방지하기 위해 서버측 동작을 변경

  • preflight를 발생시키지 않는 simple request가 되도록 요청을 변경

이것이 가능하지 않은 경우 다른 방법도 있습니다.

  1. Fetch API를 통해 Response.url (en-US) 이나 XMLHttpRequest.responseURL (en-US)를 사용하여 simple request 를 작성합니다. 이 simple request를 이용하여 실제 preflighted request가 끝나는 URL을 판별하세요.

  2. 첫 번째 단계에서 Response.url 혹은 XMLHttpRequest.responseURL 로부터 얻은 URL을 사용하여 또 다른 요청(실제 요청)을 만듭니다.

그러나 요청에 Authorization 헤더가 있기 때문에 preflight를 트리거하는 요청일 경우에, 위의 단계를 사용하여 제한을 제거할 수 없습니다. 또한 요청이 있는 서버를 제어하지 않으면 문제를 해결할 수 없습니다.

인증 정보를 포함한 요청

credential requestshttp cookieshttp authentication 정보를 인식합니다. 기본적으로 cross-site XMLHttpRequestFetch 호출에서 브라우저는 자격 증명을 보내지 않습니다. XMLHttpRequest 객체나 Request 생성자가 호출될 때 특정 플래그를 설정해야 합니다.

CORS diagram

요청에 withCredentials: true 나 쿠키가 포함되어 있더라도, 응답 헤더에 Access-Control-Allow-Credentials: true 가 포함되어 있지 않으면 응답이 무시되고 웹 컨텐츠는 제공되지 않습니다.

실행 전 요청 및 자격 증명

CORS 실행 전 요청에는 자격증명이 포함되지 않아야 합니다. 실행 전 요청에 대한 응답은 Access-Control-Allow-Credentials: true 를 지정하여 실제 요청을 수행할 수 있음을 나타내야 합니다.

자격증명 요청 및 와일드카드

자격 증명 요청에 응답할 때 서버는 반드시 * 와일드 카드를 지정하는 대신 Access-Control-Allow-Origin 헤더값에 출처를 지정해야 합니다.

위와 같이 쿠키가 포함된 헤더가 요청에 포함될 경우, Access-Control-Allow-Origin 헤더에 와일드카드값이 지정되면 요청이 실패합니다.

Third-party cookies
CORS 응답에 설정된 쿠키에는 일반적인 third-party cookie 정책이 적용됩니다.

HTTP 응답 헤더

다음은 Cross-Origin 리소스 공유 명세에 정의된 대로 서버가 접근 제어 요청을 위해 보내는 HTTP 응답 헤더가 나열되어 있습니다.

Access-Control-Allow-Origin

리턴된 리소스에는 다음 구문과 함께 하나의 Access-Control-Allow-Origin 헤더가 있을 수 있습니다.

Access-Control-Allow-Origin: origin *

Access-Control-Allow-Origin 은 단일 출처를 지정하여 브라우저가 해당 출처가 리소스에 접근하도록 허용합니다. 또는 자격 증명이 없는 요청의 경우 “*” 와일드 카드는 브라우저의 origin에 상관없이 모든 리소스에 접근하도록 허용합니다.

서버가 “*” 와일드카드 대신에 하나의 origin을 지정하는 경우, 서버는 Vary 응답 헤더에 Origin 을 포함해야 합니다. 이 origin은 화이트 리스트의 일부로 요청 orgin에 따라 동적으로 변경될 수 있습니다. 서버 응답이 Origin 요청 헤더에 따라 다르다는것을 클라이언트에 알려줍니다.

Access-Control-Expose-Headers

Access-Control-Expose-Headers 헤더를 사용하면 브라우저가 접근할 수 있는 헤더를 서버의 화이트리스트에 추가할 수 있습니다.

Access-Control-Expose-Headers: header-name[, header-name]*

예를 들면 다음과 같습니다.

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

이렇게 하면 X-My-Custom-Header 와 X-Another-Custom-Header 헤더가 브라우저에 드러납니다.

Access-Control-Max-Age

Access-Control-Max-Age (en-US) 헤더는 preflight request 요청 결과를 캐시할 수 있는 시간을 나타냅니다.

Access-Control-Max-Age: delta-seconds
delta-seconds 파라미터는 결과를 캐시할 수 있는 시간(초)를 나타냅니다.

Access-Control-Allow-Credentials

Access-Control-Allow-Credentials 헤더는 credentials 플래그가 true일 때 요청에 대한 응답을 표시할 수 있는지를 나타냅니다. preflight request에 대한 응답의 일부로 사용하는 경우, credentials을 사용하여 실제 요청을 수행할 수 있는지를 나타냅니다. simple GET requests는 preflighted되지 않으므로 credentials이 있는 리소스를 요청하면, 이 헤더가 리소스와 함께 반환되지 않습니다. 이 헤더가 없으면 브라우저에서 응답을 무시하고 웹 컨텐츠로 반환되지 않는다는 점을 주의하세요.

Access-Control-Allow-Credentials: true

Access-Control-Allow-Methods

Access-Control-Allow-Methods (en-US) 헤더는 리소스에 접근할 때 허용되는 메서드를 지정합니다. 이 헤더는 preflight request에 대한 응답으로 사용됩니다. 요청이 preflighted 되는 조건은 위에 설명되어 있습니다.

Access-Control-Allow-Methods: method[, method]*

Access-Control-Allow-Headers

preflight request 에 대한 응답으로 Access-Control-Allow-Headers 헤더가 사용됩니다. 실제 요청시 사용할 수 있는 HTTP 헤더를 나타냅니다.

Access-Control-Allow-Headers: header-name[, header-name]*

HTTP 요청 헤더

다음은 cross-origin 공유 기능을 사용하기 위해 클라이언트가 HTTP 요청을 발행할 때 사용할 수 있는 헤더들 입니다. 이 헤더는 서버를 호출할 때 설정됩니다. cross-site XMLHttpRequest 기능을 사용하는 개발자는 프로그래밍 방식으로 cross-origin 공유 요청 헤더를 설정할 필요가 없습니다.

Origin

Origin 헤더는 cross-site 접근 요청 또는 preflight request의 출처를 나타냅니다.

Origin: origin

origin 은 요청이 시작된 서버를 나타내는 URI 입니다. 경로 정보는 포함하지 않고, 오직 서버 이름만 포함합니다.
*origin 값은 null 또는 URI가 올 수 있습니다.

접근 제어 요청에는 항상 Origin 헤더가 전송됩니다.

Access-Control-Request-Method

Access-Control-Request-Method 헤더는 실제 요청에서 어떤 HTTP 메서드를 사용할지 서버에게 알려주기 위해, preflight request 할 때에 사용됩니다.

Access-Control-Request-Method: method

Access-Control-Request-Headers

Access-Control-Request-Headers 헤더는 실제 요청에서 어떤 HTTP 헤더를 사용할지 서버에게 알려주기 위해, preflight request 할 때에 사용됩니다.

Access-Control-Request-Headers: field-name[, field-name]*

Tags: ,

Categories:

Updated: