Kennen Sie den Unterschied zwischen einfacher HTTP- und XHR-Anfrage.
Origin-Web-App – https://github.com
Wenn Sie eine Website öffnen, indem Sie „Origin Web App“ eingeben, sendet Ihr Browser einfache HTTP-Anfragen. CORS ist hier nicht anwendbar. Da wir freiwillig darum bitten, Inhalte von Origin Web App bereitzustellen. Ihr Browser wird/sollte es ohne Probleme bedienen. Wenn es jedoch um XHR-Anfragen geht, kann JavaScript, das von Origin Web App in Ihren Browser geladen wird, eine Anfrage an jeden Server (https://netflix.com) stellen, der eine Ressource anfordert. Jetzt gehört Origin Web App Github, aber https://netflix.com ist Eigentum von Netflix, dieser Server könnte potenziell alles bedienen. Github kann nicht die Kontrolle über einen Server übernehmen, der Netflix gehört. Dies hat zahlreiche Auswirkungen auf die Sicherheit und kann dazu führen, dass Inhalte von einer Website (z. B. einer Finanzwebsite) auf einen beliebigen Remote-Server gestohlen werden.
Glücklicherweise löst CORS dieses Problem mit einem vorgegebenen Regelwerk sehr gut.
Es handelt sich um einen vom W3C definierten Standard, der ursprungsübergreifende Anfragen zwischen Client (Browser) und Server ermöglicht, um Ressourcen gemeinsam zu nutzen und gleichzeitig die Sicherheit zu gewährleisten. Jeder Browser entspricht diesen Standards, um das Laden von Ressourcen von Servern Dritter zu verhindern.
Ein Header gibt an, woher eine Anfrage stammt. Es wird sowohl bei CORS-Anfragen als auch bei POST-Anfragen gesendet.
Syntax:
Origin: <scheme> "://" <hostname> [":" <port> ]
Beispiele:
Origin: https://netflix.com
Origin: http://netflix.com:443
Origin: http://localhost:1443
Dieser Header wird vom Browser verwendet, wenn er Preflight-Anfragen ausgibt, um anzugeben, welche Anfragemethode verwendet wird, wenn die eigentliche Anfrage gestellt wird.
Syntax:
Access-Control-Request-Method: <method>
<method>
kann entweder GET
, POST
oder DELETE
sein.
Beispiel:
Access-Control-Request-Method: POST
Dieser Header wird erneut in den Preflight-Anfragen des Browsers verwendet, um anzugeben, welche Anfrageheader verwendet werden sollen, wenn die eigentliche Anfrage gestellt wird. Um mehrere Header zu verwenden, müssen diese durch Komma getrennt werden.
Syntax:
Access-Control-Request-Headers: <header-name>
Access-Control-Request-Headers: <header-name>, <header-name>
Beispiel:
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Wichtig: Der gesamte Header sollte auf der CORS-Sicherheitsliste stehen oder ein benutzerdefinierter Header wie X-Custom-Header
sein.
Accept
Accept-Language
Content-Language
Content-Type
Zulässige Werte sind application/x-www-form-urlencoded
, multipart/form-data
und text/plain
.
Die folgenden Header werden in den Preflight-Anfragen zurückgegeben.
Dieser Header gibt an, ob der angeforderte Ursprung zulässig ist. Ihr Browser entscheidet, ob die Anfrage erfolgreich ist oder nicht, indem er den angeforderten Ursprung damit abgleicht.
Syntax:
Access-Control-Allow-Origin: *
Für Anfragen ohne Zugangsdaten kann der Wert *
als Platzhalter angegeben werden. Dadurch wird Ihr Browser angewiesen, Anfragen von jedem Origin zuzulassen.
Access-Control-Allow-Origin: <origin>
Wenn Sie im Antwortheader nur einen Ursprung erhalten, bedeutet dies, dass Ihr Server/Ihre Web-App basierend auf dem angeforderten Origin
mit demselben Origin
antwortet, sofern dies zulässig ist. Ihr Server sollte außerdem mit „Vary“ antworten, um anzuzeigen, dass er je nach Anforderungsheader variiert.
Beispiel:
Access-Control-Allow-Origin: https://github.com
Ihr Browser stellt eine tatsächliche Anfrage, wenn einer der Werte in diesem Header übereinstimmt. Wenn der Platzhalter *
zurückgegeben wird, bedeutet dies, dass jede Methode zulässig ist.
Syntax:
Access-Control-Allow-Methods: <method>, <method>, ...
Access-Control-Allow-Methods: *
Beispiel:
Access-Control-Allow-Methods: GET, POST
Ihr Browser wird eine tatsächliche Anfrage stellen, wenn alle angeforderten Header zulässig sind.
Syntax:
Access-Control-Allow-Headers: <header-name>, <header-name>
Access-Control-Allow-Headers: *
Beispiel:
Access-Control-Allow-Headers: Accept, Content-Type
Platzhalter *
teilt dem Browser mit, dass jeder Header zulässig ist.
Gibt an, wie lange die Ergebnisse des Vorflugs zwischengespeichert werden können.
Access-Control-Max-Age: <delta-seconds>
maximale Anzahl Sekunden können die Ergebnisse zwischengespeichert werden.
Jeder Browser hat ein maximales Limit.
Vary-Header werden im Allgemeinen für Caching-Zwecke verwendet, um anhand des Header-Werts zu bestimmen, ob eine zwischengespeicherte Antwort verwendet werden kann oder erneut zwischengespeichert werden muss.
Nehmen wir in CORS an, der Server lässt mehrere Ursprünge basierend auf dem angeforderten Origin
zu und gibt eine bestimmte URL in Access-Control-Allow-Origin
zurück.
Syntax:
Vary: <header-name>
Beispiel:
Nehmen wir an, github.com erlaubt sowohl https://github.com als auch https://netflix.com, Ressourcen anzufordern. Betrachten Sie die folgenden Szenarien:
Szenario 1:
curl -X OPTIONEN https://github.com/api/v1/gists/1
Origin: https://github.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type
Access-Control-Allow-Origin: https://github.com
Vary: Origin
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 600
In diesem Szenario speichert der Browser die Ergebnisse der Preflight-Anfrage nun 10 Minuten lang zwischen.
Szenario 2:
curl -X OPTIONEN https://github.com/api/v1/gists/1
Origin: https://netflix.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type
Access-Control-Allow-Origin: https://netflix.com
Vary: Origin
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 300
Jetzt könnten Sie feststellen, dass Access-Control-Allow-Origin
https://netflix.com enthält. Dies ist ein Beispiel dafür, wie die Antwort je nach angegebenem Origin
variiert. Dies gilt auch für das maximale Alter dieser Antwort, die im Gegensatz zum ersten Szenario nur 5 Minuten lang zwischengespeichert wird.
Einige Anfragen lösen keine Vorfluganfrage für CORS aus. Diese nennen wir einfache Anfragen . Es sollte die folgenden Bedingungen erfüllen:
Eine der erlaubten Methoden:
Abgesehen von Headern, die automatisch vom Benutzeragenten erstellt werden (z. B. Connection
oder User-Agent
), sind die einzigen Header, die manuell festgelegt werden dürfen, CORS-sichere Anforderungsheader und die folgenden:
DPR
Downlink
Save-Data
Viewport-Width
Width
Für kein in der Anforderung verwendetes XMLHttpRequestUpload
Objekt sind Ereignis-Listener registriert.
In der Anfrage wird kein ReadableStream
-Objekt verwendet.
Beispiel:
Anfrage:
GET /api/v1/public-data/ HTTP/1.1
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
Antwortheader:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
Wenn eine Anfrage ein *
im Access-Control-Allow-Origin
Header zurückgibt. Dies bedeutet, dass eine Anfrage von jedem Host
gestellt werden kann. In diesem Fall stellt Ihr Browser keine Preflight-Anfrage.
Ihr Browser stellt vor dem Flug eine Anfrage, um festzustellen, ob die tatsächliche Anfrage sicher gesendet werden kann.
Beispiel:
const xhr = new XMLHttpRequest ( ) ;
xhr . open ( 'POST' , 'https://bar.com/api/v1/post-here/' ) ;
xhr . setRequestHeader ( 'X-PINGOTHER' , 'pingpong' ) ;
xhr . setRequestHeader ( 'Content-Type' , 'application/json;charset=UTF-8' ) ;
xhr . onreadystatechange = handler ;
xhr . send ( JSON . stringify ( { "email" : "[email protected]" } ) ) ;
Anfrage vor dem Flug:
OPTIONS /api/v1/post-here/
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: application/json
Access-Control-Allow-Origin: https://foo.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type, Accept
Tatsächliche Anfrage:
POST -d '{foo: bar}' /api/v1/post-here/
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
X-PINGOTHER: pingpong
Content-Type: application/json;charset=UTF-8
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: application/json
Access-Control-Allow-Origin: https://foo.com
Wenn ein nicht standardmäßiger Header wie X-PINGOTHER
festgelegt ist, weiß Ihr Browser nicht, ob die Anfrage sicher ist. Um die Sicherheit zu gewährleisten, sendet Ihr Browser eine OPTIONS-Anfrage mit Access-Control-Request-Headers
X-PINGOTHER
und Content-Type
enthalten. Nach der Validierung mit Antwortheadern der Pre-Flight-Anfrage sendet Ihr Browser die tatsächliche Anfrage.
Wenn Sie eine XHR-Anfrage stellen, werden im Allgemeinen keine Cookies mit der Anfrage weitergegeben. Wenn Cookies übergeben werden müssen, müssen Sie ein Flag für das XMLHttpRequest
Objekt setzen.
const xhr = new XMLHttpRequest ( ) ;
const url = 'http://bar.com/api/v1/credentialed-content/' ;
function callOtherDomain ( ) {
if ( invocation ) {
xhr . open ( 'GET' , url , true ) ;
xhr . withCredentials = true ;
xhr . onreadystatechange = handler ;
xhr . send ( ) ;
}
}
Anfrage:
POST -d '{foo: bar}' /api/v1/post-here/
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
X-PINGOTHER: pingpong
Content-Type: application/json;charset=UTF-8
Cookie: _session=NyV14oKXiS6HHopaf9nT
Wenn eine Anfrage per XMLHttpRequest
gestellt wird und withCredentials
-Flag gesetzt ist, übergibt Ihr Browser das Cookie
im Anfrageheader.
Antwort:
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: application/json
Access-Control-Allow-Origin: https://foo.com
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: _session=AjBSqxj4T7bSySNTWeEm; expires=Wed, 31-05-2020 00:00:00 GMT
Wenn Ihr Browser feststellt, dass Access-Control-Allow-Credentials
auf „true“ gesetzt ist. Es respektiert Set-Cookie
Header und setzt das Cookie.
Wichtig: Der Platzhalter „*“ sollte nicht im Access-Control-Allow-Origin
festgelegt werden, wie im Abschnitt Berechtigte Anfragen und Platzhalter erwähnt.
Wenn eine Anmeldeinformationsanforderung durch Setzen withCredentials
-Flags gestellt wird, muss Access-Control-Expose-Headers
vom Server festgelegt werden, um dem Browser mitzuteilen, auf welche Header zugegriffen werden kann.
In der Vor-Cors-Welt sind Antwortheader in der CORS-Anfrage standardmäßig nicht für den Browser zugänglich. Daher wird es explizit gemacht, sodass der Browser nach diesem Header sucht, um offengelegte Header zu lesen. Auf diese Weise stellt die CORS-Spezifikation sicher, dass alte Browser nicht kaputt gehen.
Dies wird in den Preflight-Anfragen zurückgegeben. Wenn Ihr Browser dies sieht, kann er auf Set-Cookie
-Header zugreifen. Wie oben erwähnt, übergibt Ihr Browser bei normalen XHR-Anfragen kein Cookie
im Anforderungsheader und liest auch nicht Set-Cookie
-Antwortheader.
Syntax:
Access-Control-Allow-Credentials: true
Ein Beispiel finden Sie im Abschnitt „Anfrage mit Anmeldeinformationen“.
Wenn wir „anmeldepflichtige Anfrage“ sagen, bedeutet dies, dass Cookies in der XHR-Anfrage übergeben oder über den Antwortheader „ Set-Cookie
gesetzt werden. Wenn eine XHR-Anfrage mit dem Flag „withCredentials“ gestellt wird, hoffen Sie, eine Antwort zusammen mit zu setzenden Cookies zu erhalten. Sie können jedoch nicht erwarten, dass Access-Control-Allow-Origin
„*“ ist, da dies bedeuten würde, dass jede Website diese Cookies verwenden kann. Aus diesem Grund schlägt Ihr Browser bei der Anfrage fehl, wenn er „*“ im Access-Control-Allow-Origin
Antwortheader sieht.
Wenn eine Preflight-Anfrage mit 301/302 antwortet, unterstützen einige Browser dies derzeit möglicherweise nicht. Möglicherweise erhalten Sie Fehler wie:
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
Hinweis: Informationen zu Problemumgehungen finden Sie in den Preflight-Anfragen und Weiterleitungsdokumenten von Mozilla.
Der Browser verfügt über Einstellungen zur Ablehnung aller Cookies third-party
, wenn ein Benutzer dies aktiviert. Wenn beispielsweise eine Anfrage von https://foo.com
gestellt wird und sich der Server unter https://bar.com
befindet, setzt Ihr Browser keine von https://bar.com
gesendeten Cookies.