Cross-Origin Resource Sharing (CORS)
CORS (CROSS-Origin Resource Sharing)는 HTTP 헤더 기반 메커니즘으로, 모든 브라우저가 리소스 로딩을 허용해야 하는 자체(origin) 출처 이외에 다른 출처(도메인, 스키마, 또는 포트)를 서버가 표시할 수 있도록 한다. CORS는 또한 서버가 실제 요청을 허용하는지 체크하기 위해서 브라우저가 cross-origin 리소스를 호스팅하는 서버에 요청하기 위해 만든 “preflight(실행 전)“ 요청 메커니즘에 의존한다. 해당 preflight에서, 브라우저는 HTTP 메서드를 나타내는 헤더와 실제 요청에서 사용될 헤더를 보낸다.
즉, 웹 애플리케이션은 리소스가 자신의 출처와 다를 때 CORS HTTP 요청을 실행한다.
cross-origin 요청의 예시 : https://domain-a.com에서 받은 front-end JavaScript 코드가 XMLHttpRequest를 사용하여 https://domain-b.com/data.json을 요청하는 경우.
보안상의 이유로, 브라우저는 스크립트에서 처음 시작된 cross-origin HTTP 요청을 제한한다. 예를들어, XMLHttpRequest 와 Fetch API는 same-origin 정책을 따른다. 즉, 해당 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 한다.
CORS는 브라우저와 서버 간의 안전한 cross-origin 요청 및 데이터 전송을 지원한다. 최신 브라우저들은 XMLHttpRequest나 Fetch와 같은 API에서 CORS를 사용해 cross-origin HTTP 요청의 위험을 완화시킨다.
기능 개요
Cross-Origin Resource Sharing 표준은 웹 브라우저에서 해당 정보를 읽는 것이 허용된 출처를 서버에서 알려주는 새로운 HTTP 헤더를 추가함으로써 동작합니다. 추가적으로, 서버 데이터에 부작용을 일으킬 수 있는 HTTP 요청 메서드(GET을 제외한 HTTP 메서드)에 대해, CORS 명세는 브라우저가 요청을 OPTIONS 메서드로 "preflight"(사전 전달)하여 지원하는 메서드를 요청하고, 서버의 “credentials(승인)”가 떨어지면 실제 요청을 보내도록 요구하고 있다. 또한 서버는 클라이언트에게 요청에 "인증정보"(쿠키나 HTTP Authentication)를 함께 보내야 한다고 알려줄 수도 있다.
CORS 오류의 원인은 보안상의 이유로 JavaScript에서 세부 정보를 확인할 수 없다. 오류가 발생했다는 것만 알 수 있다. 구체적으로 어떤 내용이 잘못되었는지 확인하는 방법은 브라우저의 콘솔에서 확인하는 것이다.
접근 제어 시나리오 예시
CORS가 어떻게 작동하는지 보여주는 3가지 예시이다.
Simple requests (단순 요청)
simple requests는 CORS preflight를 발생시키지 않는다.
simple requests는 다음 조건을 모두 충족하는 요청이다.
- 다음 중 하나의 메서드
- GET
- HEAD
- POST
- 설정 한 헤더(예: Connection, User-Agent 또는 Fetch 명세에서 “forbidden header name”으로 정의한 헤더) 외에, 수동으로 설정할 수 있는 유일한 헤더는 Fetch명세에서 “CORS-stfelisted request-header”로 정의한 헤더이다.
- Accept
- Accept-Language
- Content-Language
- Content-Type
- Content-Type헤더는 아래의 값들만 허용된다.
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
예를들어, https://foo.example 의 웹 컨텐츠가 https://bar.other 도메인의 컨텐츠를 호출하길 원한다고 하자. foo.example에 배포된 자바스크립트에는 아래와 같은 코드가 사용될 수 있다.
const xhr = new XMLHttpRequest();
const url = 'https://bar.other/resources/public-data/';
xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();
클라이언트와 서버 간에 간단한 통신을 하고, CORS 헤더를 사용하여 권한을 처리한다.
이 경우 브라우저가 서버로 전송하는 내용을 살펴보고, 서버의 응답을 확인한다.
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
서버는 응답으로 Access-Control-Allow-Origin 헤더를 다시 전송한다. 가장 간단한 접근 제어 프로토콜은 Origin 헤더와 Access-Control-Allow-Origin 을 사용하는 것이다. 이 경우 서버는 Access-Control-Allow-Origin: *, 으로 응답해야 하며, 이는 모든 도메인에서 접근할 수 있음을 의미한다. https://bar.other 의 리소스 소유자가 오직 https://foo.example 의 요청만 리소스에 대한 접근을 허용하려는 경우 다음을 전송한다.
Access-Control-Allow-Origin: https://foo.example
이제 https://foo.example 이외의 도메인은 cross-site 방식으로 리소스에 접근할 수 없습니다. 리소스에 대한 접근을 허용하려면, Access-Control-Allow-Origin 헤더에는 요청의 Origin 헤더에서 전송된 값이 포함되어야 한다.
Preflight 요청
"preflight" 요청은 위에서 말한 “simple requests” 와는 달리, 먼저 OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인한다. cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 미리 전송(preflighted)한다.
(참고: 실제 POST 요청에는 Access-Control-Request-* 헤더가 포함되지 않는다. OPTIONS 요청에만 필요.)
1. 클라이언트와 서버 간의 완전한 통신이다. 첫 번째 통신은 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
2. preflight 요청이 완료되면 실제 요청을 전송한다.
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
[Some GZIP'd payload]
1번의 1 - 10 행은 OPTIONS 메서드를 사용한 preflight 요청을 나타낸다. 서버는 실제 요청 파라미터로 요청을 보낼 수 있는지 여부에 응답한다. OPTIONS는 서버에서 추가 정보를 판별하는데 사용하는 HTTP/1.1 메서드다. 또한 safe 메서드이기 때문에, 리소스를 변경하는데 사용할 수 없다. OPTIONS 요청과 함께 두 개의 다른 요청 헤더가 전송된다.
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Access-Control-Request-Method 헤더는 preflight 요청의 일부로, 실제 요청을 전송할 때 POST 메서드로 전송된다는 것을 알려준다. Access-Control-Request-Headers 헤더는 실제 요청을 전송 할 때 X-PINGOTHER 와 Content-Type 사용자 정의 헤더와 함께 전송된다는 것을 서버에 알려준다. 이제 서버는 이러한 상황에서 요청을 수락할지 결정할 수 있다.
1번의 13 - 22 행은 서버가 요청 메서드(POST)와 요청 헤더(X-PINGOTHER)를 받을 수 있음을 나타내는 응답이다. (16 - 19행)
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
서버는 Access-Control-Allow-Methods 로 응답하고 POST 와 GET 이 리소스를 쿼리하는데 유용한 메서드라고 가르쳐준다. 이 헤더는 Allow 응답 헤더와 유사하지만, Access-Control 컨텍스트 내에서 엄격하게 사용된다.
또한 Access-Control-Allow-Headers 의 값을 "X-PINGOTHER, Content-Type" 으로 전송하여 실제 요청에 헤더를 사용할 수 있음을 확인한다. 마지막으로 Access-Control-Max-Age (en-US)는 다른 preflight request를 보내지 않고, preflight request에 대한 응답을 캐시할 수 있는 시간(초)을 제공한다. 위의 코드는 86400 초(24시간) 이다. 각 브라우저의 최대 캐싱 시간(en-US)은 Access-Control-Max-Age 가 클수록 우선순위가 높다.
Preflighted requests 와 리다이렉트
모든 브라우저가 preflighted request 후 리다이렉트를 지원하지 않는다. preflighted request 후 리다이렉트가 발생하면 일부 브라우저는 다음과 같은 오류 메시지를 띄운다.
요청이 'https://example.com/foo'로 리다이렉트 되었으며, preflight가 필요한 cross-origin 요청은 허용되지 않습니다.
요청에 preflight가 필요합니다. preflight는 cross-origin 리다이렉트를 허용하지 않습니다.
CORS 프로토콜은 원래 리다이렉트가 필요했지만, 이후 더 이상 필요하지 않도록 변경되었다. 그러나 모든 브라우저가 변경 사항을 구현하지는 않았다.
브라우저가 명세를 따라잡을 때 까지 다음 중 하나 혹은 둘 다를 수행하여 이 제한을 해결할 수 있다.
- preflight 리다이렉트를 방지하기 위해 서버 측 동작을 변경
- preflight를 발생시키지 않는 simple request 가 되도록 요청을 변경
인증 정보를 포함한 요청
XMLHttpRequest 혹은 Fetch 를 사용할 때 CORS관련 가장 흥미로운 기능은 "credentialed" requests 이다. credentialed requests는 HTTP cookies 와 HTTP Authentication 정보를 인식한다. 기본적으로 cross-site XMLHttpRequest 나 Fetch 호출에서 브라우저는 자격 증명을 보내지 않는다. XMLHttpRequest 객체나 Request 생성자가 호출될 때 특정 플래그를 설정해야 한다.
아래에서 원래 http://foo.example 에서 불러온 컨텐츠는 쿠키를 설정하는 http://bar.other 리소스에 simple GET request를 작성한다. foo.example의 내용은 다음과 같다.
const invocation = new XMLHttpRequest();
const url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain() {
if (invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}
7행은 쿠키와 함께 호출하기위한 XMLHttpRequest 의 플래그를 보여준다. 이 플래그는 withCredentials 라고 불리며 부울 값을 갖는다. 기본적으로 호출은 쿠키 없이 이루어진다. 이것은 simple GET request이기 때문에 preflighted 되지 않는다. 그러나 브라우저는 Access-Control-Allow-Credentials: true 헤더가 없는 응답을 거부한다.
클라이언트와 서버 간의 통신 예시는 다음과 같다.
GET /resources/credentialed-content/ 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
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
Access-Control-Allow-Origin: https://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
[text/plain payload]
10행에는 http://bar.other의 컨텐츠를 대상으로 하는 쿠키가 포함되어 있습니다. 하지만 17행의 Access-Control-Allow-Credentials: true 로 응답하지 않으면, 응답은 무시되고 웹 컨텐츠는 제공되지 않는다.
실행 전 요청 및 자격 증명(Credentials)
CORS 실행 전 요청에는 자격 증명이 포함되지 않아야 한다. 실행 전 요청에 대한 응답은 Access-Control-Allow-Credentials: true를 지정하여 자격 증명으로 실제 요청을 수행할 수 있음을 나타내야 한다.
자격증명 요청 및 와일드카드(Credentialed requests and wildcards)
자격 증명 요청에 응답할 때 서버는 반드시 "*" 와일드카드를 지정하는 대신 Access-Control-Allow-Origin 헤더 값에 출처를 지정해야 한다.
위 예시의 요청 헤더에 Cookie 헤더가 포함되어 있기 때문에 Access-Control-Allow-Origin 헤더의 값이 "*"인 경우 요청이 실패한다. 위 요청은 Access-Control-Allow-Origin 헤더가 "*" 와일드 카드가 아니라 "http://foo.example" 원래 주소이기 때문에 자격 증명 인식 컨텐츠는 웹 호출 컨텐츠로 리턴된다.
위 예시의 Set-Cookie 응답 헤더는 추가 쿠키를 설정한다. 실패한 경우 사용한 API에 따라 예외가 발생한다.
HTTP 응답 헤더
Access-Control-Allow-Origin
리턴된 리소스에는 하나의 Access-Control-Allow-Origin 헤더가 있을 수 있다.
Access-Control-Allow-Origin: <origin> | *
Access-Control-Allow-Origin 은 단일 출처를 지정하여 브라우저가 해당 출처가 리소스에 접근하도록 허용한다. 자격 증명이 없는 요청의 경우 "*" 와일드 카드는 브라우저의 origin에 상관없이 모든 리소스에 접근하도록 허용한다.
예를 들어 https://example.com 의 코드가 리소스에 접근 할 수 있도록 하려면 다음과 같이 지정할 수 있다.
Access-Control-Allow-Origin: https://example.com
서버가 "*" 와일드카드 대신에 하나의 origin을 지정하는 경우, 서버는 Vary 응답 헤더에 Origin 을 포함해야 한다. 이 origin은 화이트 리스트의 일부로 요청 origin에 따라 동적으로 변경될 수 있다. 서버 응답이 Origin 요청 헤더에 따라 다르다는 것을 클라이언트에 알려준다.
Access-Control-Expose-Headers
Access-Control-Expose-Headers (en-US) 헤더를 사용하면 브라우저가 접근할 수 있는 헤더를 서버의 화이트리스트에 추가할 수 있다.
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 헤더는 리소스에 접근할 때 허용되는 메서드를 지정한다. 이 헤더는 preflight request에 대한 응답으로 사용된다.
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 요청을 발행할 때 사용할 수 있는 헤더가 나열되어 있다. 이 헤더는 서버를 호출할 때 설정된다.
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>]*
CORS errors
교차 출처 자원 공유 (CORS)는 서버가 same origin 정책(same-origin policy)을 완화할 수 있게 해 주는 표준이다. 이는 일부 교차 출처 요청은 명시적으로 허용하고 다른 요청은 거부하는 데 사용된다. 예를 들어서, 어떤 사이트가 embeddable service를 제공하는 경우, 특정 제한을 완화하는 것이 필요할 수 있다. CORS 설정을 세팅하는 것은 그리 쉬운 일이 아니며, 도전일 수 있다. 몇 가지 일반적인 CORS 에러 메시지와 그에 맞는 해결법을 보자.
만약 CORS 설정이 제대로 세팅되어 있지 않다면, 브라우저 콘솔에는 다음과 같은 메시지가 표시된다: "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at $somesite" 이 메시지는 CORS 보안 규칙 위반으로 인해 요청이 차단되었음을 알려준다. 이것은 꼭 설정 실수라고 볼 수는 없다. 사실은 해당 요청이 유저 쪽의 웹 어플리케이션과 외부 서비스에 의해 거부당했을 수 있다. 하지만 만약 엔드포인트가 사용 가능한 걸로 확인된다면, 약간의 디버깅이 필요 할 수 있다.
이슈 파악하기
CORS 설정 이슈를 근본적으로 이해하려면 어떤 요청이 문제이고 왜 문제인지를 파악할 필요가 있다.
- 웹사이트나 웹앱으로 이동하여 Developer Tools을 확인.
- 실패한 요청을 재현하고 나서 CORS 위반 에러 메시지가 떴다면 console을 확인하자. 메시지는 다음과 비슷하다.
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at https://some-url-here. (Reason:
additional information here).
CORS 에러 메시지
Firefox 콘솔은 CORS에 의해 요청이 실패했을 때 메시지를 출력한다. 에러 내용의 일부분은 "Reason"에 관한 메시지로서 무엇이 잘못 되었는지에 대한 힌트를 제공한다.
CORS를 사용해야 하는 요청이 시도되었지만 사용자 브라우저에서 CORS가 비활성화. 이 경우 사용자는 브라우저에서 CORS를 다시 켜야 한다.
네트워크 또는 프로토콜 수준에서 HTTP 연결이 실패했기 때문에 CORS를 사용하는 HTTP 요청이 실패했다. 이 에러는 근본적인 네트워크 에러이거나 그에 준하는 에러로 CORS와 직접적인 연관이 있는 것은 아니다.
사용자 에이전트가 HTTP요청에 필요한 Origin헤더를 추가할 수 없기때문이다. 모든 CORS 요청에는 Origin헤더가 있어야 한다.
CORS 요청이 CORS요청 중에 허용하지 않은 원래 요청과 다른 origin URL에 대한 HTTP redirect를 사용해 서버에 응답했다.
예를들어, 페이지 https://service.tld/fetchdata 가 요청되고, HTTP응답이 https://anotherservice.net/getdata의 Location "301 Moved Permanently", "307 Temporary Redirect" 또는 "308 Permanent Redirect"일 때, CORS 요청은 이런 방식으로 실패한다.
문제를 해결하려면, 리디렉션에서 보고된 새 URL을 사용하도록 코드를 업데이트하여 리디렉션을 방지하자.
CORS 요청은 오직 HTTPS URL 스키마만을 사용할 수 있지만 요청에 의해 지정된 URL이 다른 타입일때 발생. 종종 URL이 file:/// URL을 사용해 로컬 파일을 지정할 경우 발생한다.
문제를 해결하려면, XMLHttpRequest, Fetch APIs, 웹 폰트(@font-face), WebGL textures, XSL 스타일시트와 같은 CORS를 포함하는 요청이 발생할 때 HTTPS URL을 사용하고 있는지 확인하도록 한다.
CORS 요청에 대한 응답에 현재 origin 내에서 작동하는 콘텐츠가 리소스에 접근할 수 있는지 결정하는데 사용되는 필수 Access-Control-Allow-Origin헤더가 없을 때 발생.
서버가 사용자의 제어하에 있는 경우, 요청 사이트의 origin을 Access-Control-Allow-Origin 헤더 값에 추가하여 접근이 허용된 도메인 집합에 추가한다.
Access-Control-Allow-Origin요청을 보내는 origin이 허용하는 origin과 일치하지 않을 때 발생. 이 오류는 응답에 두 개 이상의 Access-Control-Allow-Origin헤더가 포함된 경우에도 발생할 수 있다.
코드가 접근하려는 서비스가 CORS 요청을 사용하는경우, Access-Control-Allow-Origin헤더에 origin을 포함하도록 구성되어있는지 확인해야한다. 또한, response에 헤더가 하나만 포함되어있고, 단일 origin만 포함되어잇는지 확인해야한다.
CORS요청이 자격증명 플래그가 설정된 상태에서 요청했지만, 서버는 자격증명 사용을 허용하지 않는 Access-Control-Allow-Origin 값으로 와일드카드 (*)를 사용하여 구성되었을때.
클라이언트 측에서 이 문제를 해결하려면, CORS 요청을 만들때 자격 증명 플래그의 값으로 false가 있는지 확인해야한다.
- XMLHttpRequest를 사용하여 요청할때 문제가 생기면, withCredentials를 true로 설정하지 않았는지 확인
- Server0sent events를 사용하는 경우, EventSource.withCredentials가 false인지 확인(기본값).
- Fetch API를 사용하는 경우, Request.credentials가 "omit"인지 확인.
대신, 서버의 동작을 조정해야 하는 경우, 클라이언트가 로드하는 원본에 대한 액세스 권한을 부여하도록 Access-Control-Allow-Origin의 값을 변경해야한다.
CORS 요청에서 사용 중인 HTTP 메서드가 응답 Access-Control-Allow-Methods헤더에 지정된 메서드 목록에 포함되어 있지 않을때. 이 헤더는 CORS를 사용하여 요청에 지정된 URL에 접근할 때 사용할 수 있는 HTTP 메소드의 쉼표로 구분된 리스트를 지정한다. 만약 요청이 다른 방법을 사용하는 경우 이 오류가 발생한다.
CORS 요청은 서버가 자격증명 사용을 허용하도록 요청하지만, 서버의 Control-Allow-Credentials 헤더의 값이 자격증명 사용이 true로 설정되지 않았기 때문.
클라이언트 쪽에서 문제를 해결하려면, 자격 증명 사용을 요청하지 않도록 코드를 수정해야한다.
- XMLHttpRequest 을 사용하여 요청하는 경우로, withCredentials가 true로 설정하지 않았는지 확인.
- Server-sent event를 사용하는 경우 EventSource.withCredentials 가 false 인지 확인(기본값).
- Fetch API를 사용하는 경우 Request.credentials가 "omit"인지 확인.
서버 구성을 변경하여 에러를 제거하려면, Access-Control-Allow-Credentials 헤더값을 true 설정하여 서버 구성을 조정.
CORS 요청에 preflight가 필요하며, preflight를 수행할 수 없을 때 발생.
preflight가 실패하는 몇가지 이유가 있다.
- 이전에 이미 preflight를 수행한 교차 사이트 요청이며, preflight를 다시 수행하는 것이 허용되지 않을때. 코드가 연결 당 한 번만 preflight되는지 확인해야 한다.
- preflight 요청에 일반적으로 발생할 수 있는 모든 종류의 네트워크 오류가 발생했을때.
서버에서 보낸 CORS 요청에 대한 응답에 하나 이상의 잘못된 메서드 이름이 포함된 Access-Control-Allow-Methods 헤더가 포함되어 있을때.
Access-Control-Allow-Methods 헤더는 클라이언트에 HTTP 요청 메서드를 알리기 위해 서버에 의해 보내진다. 헤더의 값은 GET, POST, HEAD와 같이 HTTP메서드 이름의 쉼표로 구분된 문자열이다. 사용자 에이전트에서 지정된 값을 인식하지 못하는 경우 이 오류가 발생한다.
이 문제는 Access-Control-Allow-Methods헤더에 유효하지 않거나 알 수 없는 메서드 이름을 보내지 않도록 서버의 구성을 수정하해야하고, 서버측에서 해결할 수 있는 문제이다. 클라이언트에서 사용중인 사용자 에이전트 또는 HTTP 라이브러리가 최신인지 확인도 해야한다.
서버에서 보낸 Access-Control-Allow-Headers헤더가 포함된 CORS 요청에 대한 응답에 잘못된 헤더 이름이 포함되어 있을때 발생.
Access-Control-Allow-Headers헤더는 preflight 요청에 대한 응답으로 서버에 전송된다. 이를 통해 클라이언트는 CORS 요청에서 허용되는 HTTP헤더를 알 수 있다. 클라이언트 사용자 에이전트가 헤더에서 제공하는 쉼표로 구분된 값 중에서 인식하지 못하는 헤더 이름을 찾으면 이 오류가 발생한다.
이 문제는 Access-Control-Allow-Headers헤더와 함께 유효하지 않거나 알 수 없는 헤더 이름을 더 이상 보내지 않도록 서버 구성을 수정하여 서버측에서만 해결할 수 있는 문제이다. 클라이언트에서 사용중인 사용자 에이전트 또는 HTTP 라이브러리가 최신인지 확인도 해야한다.
Access-Control-Allow-Headers헤더는 클라이언트가 CORS 요청에 지원하는 헤더를 알 수 있도록 서버에 의해 전송된다. Access-Control-Allow-Headers의 값은 X-Custom-Information나 기본이 아닌 헤더이름과 같이 쉼표로 구분된 목록이어야 한다.
이 오류는 허용되지 않은 (즉, 서버에서 보낸 헤더에 지정된 목록에 포함되지 않은) 헤더를 preflight하려할 때 발생한다. 이 문제를 해결하려면, 서버를 업데이트하여 헤더를 허용하게하거나, 오류가 나는 헤더를 사용하지 않아야한다.
서버에서 둘 이상의 Access-Control-Allow-Origin헤더를 보낼때. 이것은 허용되지 않는다.
Access-Control-Allow-Origin서버에 대한 액세스 권한이 있는 경우 헤더의 origin을 재전달하도록 변경할 수 있다 . 브라우저는 단일 출처 또는 null 값만 허용하므로 출처 목록을 다시 보낼 수 없다.