cors: Korrektes CORS für NGINX, einschließlich Preflight und Vary
Erfordert den Pro-Plan (oder höher) des GetPageSpeed NGINX Extras-Abonnements.
Installation
Sie können dieses Modul in jeder RHEL-basierten Distribution installieren, einschließlich, aber nicht beschränkt auf:
- RedHat Enterprise Linux 7, 8, 9 und 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 und Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-cors
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-cors
Aktivieren Sie das Modul, indem Sie Folgendes am Anfang von /etc/nginx/nginx.conf hinzufügen:
load_module modules/ngx_http_cors_module.so;
Dieses Dokument beschreibt nginx-module-cors v1.0.0 veröffentlicht am 15. August 2026.
CORS für NGINX, das die Teile korrekt behandelt, die das add_header-Rezept falsch macht.
Warum nicht einfach add_header verwenden?
Das map $http_origin + add_header Access-Control-Allow-*-Rezept wird von
jedem kopiert, und es ist auf vier spezifische Arten fehlerhaft:
add_headerwird pro Ebene vererbt oder ersetzt. Sobald einlocationeinen eigenen Header hinzufügt, verschwinden alleadd_header-Anweisungen darüber — einschließlich Ihrer CORS-Header — stillschweigend. Nichts warnt Sie.- Preflight benötigt einen Kurzschluss. Eine
OPTIONS-Preflight-Anfrage muss mit einem204und den richtigen Headern beantwortet werden, ohne Ihre Anwendung zu erreichen. Das von Hand zu tun bedeutet einenif-Block, und dieser interagiert schlecht mittry_filesundproxy_pass. add_headerfeuert nur auf einer Whitelist von Statuscodes, es sei denn, Sie übergebenalways. Dadurch verlieren Ihre Fehlerantworten ihre CORS-Header, und der Browser meldet einen undurchsichtigen CORS-Fehler anstelle des tatsächlich aufgetretenen 404 oder 502.Vary: Originwird vergessen. Wenn die Antwort vom Ursprung der Anfrage abhängt und Sie dies nicht angeben, wird jeder vorgeschaltete gemeinsame Cache oder jedes CDN die Antwort eines Ursprungs bereitwillig einem anderen ausliefern. Dies ist ein Cache-Poisoning-Fehler und der häufigste in der Praxis.
Dieses Modul erledigt alle vier Punkte korrekt, als Header-Filter plus einen
Preaccess-Phasen-Handler, ohne if-Blöcke.
Übersicht
location /api/ {
cors on;
cors_origin https://app.example.com https://*.staging.example.com;
cors_methods GET HEAD POST PUT DELETE;
cors_headers Authorization Content-Type;
cors_expose_headers X-Total-Count;
cors_credentials on;
cors_max_age 86400;
proxy_pass http://backend;
}
Eine Preflight-Anfrage sieht dann wie folgt aus und erreicht backend nie:
$ curl -i -X OPTIONS https://api.example.com/api/things \
-H 'Origin: https://app.example.com' \
-H 'Access-Control-Request-Method: PUT'
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400
Vary: Origin, Access-Control-Request-Method
Direktiven
cors
Syntax: cors on | off;
Standard: cors off;
Kontext: http, server, location, if in location
Aktiviert die CORS-Verarbeitung. Jede andere Direktive wird unabhängig vererbt,
sodass ein verschachtelter location, der eine davon setzt, den Rest nicht
verliert — das ist der entscheidende Unterschied zu add_header.
cors_origin
Syntax: cors_origin * | any | <spezifikation> ...;
Standard: cors_origin *;
Kontext: http, server, location, if in location
Welche Ursprünge die Ressource lesen dürfen. Zwei reservierte Wörter und drei Spezifikationsformen:
| Wert | Bedeutung |
|---|---|
* |
Einen wörtlichen Access-Control-Allow-Origin: * ausgeben. Gleich für alle, daher wird kein Vary: Origin hinzugefügt. Kann nicht mit cors_credentials on kombiniert werden. |
any |
Den eingehenden Origin zurückspiegeln. Credential-sicher, gibt Vary: Origin aus. |
https://app.example.com |
Exakte Übereinstimmung, case-insensitiv. |
https://*.example.com |
Wildcard-Subdomain. |
~^https://(a\|b)\.example\.com$ |
Regulärer Ausdruck. ~* für case-insensitiv. |
Mehrere Spezifikationen können aufgelistet werden. Wenn eine übereinstimmt,
wird dieser Ursprung zurückgegeben. * und any können nicht mit anderen
Werten gemischt werden.
Wildcards sind bewusst streng: Das * muss direkt nach :// stehen und von
einem . gefolgt werden. https://*example.com wird beim Start abgelehnt,
anstatt stillschweigend https://evilexample.com zu matchen. Eine Wildcard
matcht eine beliebige Anzahl führender Labels (https://a.b.example.com
matcht https://*.example.com), matcht aber nicht die nackte Apex-Domain und
ignoriert keinen Port — ein Ursprung mit Port benötigt einen exakten Eintrag
oder einen regulären Ausdruck.
Origin: null — was ein sandboxed iframe, ein data:-Dokument oder eine
file://-Seite sendet — wird nur durch einen expliziten null-Eintrag in der
Liste gematcht, wenn cors_credentials on ist. Weder any noch ein regulärer
Ausdruck matcht es in diesem Fall. Das Zurückspiegeln von null mit
Credentials würde jedem sandboxed Frame im Internet einen authentifizierten
Lesezugriff auf die Antwort geben.
cors_methods
Syntax: cors_methods * | <methode> ...;
Standard: cors_methods GET HEAD POST OPTIONS;
Kontext: http, server, location, if in location
Der Access-Control-Allow-Methods-Wert, der bei einer Preflight-Anfrage
gesendet wird. * kann nicht mit cors_credentials on kombiniert werden.
cors_headers
Syntax: cors_headers * | any | <name> ...;
Standard: — (der Header wird weggelassen)
Kontext: http, server, location, if in location
Der Access-Control-Allow-Headers-Wert, der bei einer Preflight-Anfrage
gesendet wird. any spiegelt den Access-Control-Request-Headers der Anfrage
wörtlich zurück; der Header wird weggelassen, wenn die Anfrage keine angefordert
hat. * kann nicht mit cors_credentials on kombiniert werden.
cors_expose_headers
Syntax: cors_expose_headers <name> ...;
Standard: — (der Header wird weggelassen)
Kontext: http, server, location, if in location
Antwort-Header, die der Browser für Skripte lesbar machen soll, über die Safelist-Menge hinaus. Wird bei tatsächlichen Antworten gesendet, nicht bei Preflight-Anfragen.
cors_credentials
Syntax: cors_credentials on | off;
Standard: cors_credentials off;
Kontext: http, server, location, if in location
Gibt Access-Control-Allow-Credentials: true aus und erlaubt Cookies und
HTTP-Authentifizierung bei Cross-Origin-Anfragen.
Die CORS-Spezifikation verbietet die Kombination von Credentials mit einer Wildcard, und jeder Browser setzt dies durch — eine Konfiguration, die beides tut, ist also eine Konfiguration, deren CORS nie funktioniert. NGINX weigert sich zu starten, anstatt Ihnen die Auslieferung zu erlauben:
cors_credentials on;
cors_origin *; # nginx: [emerg] ... cannot be combined with "cors_origin *"
Verwenden Sie eine explizite Liste oder cors_origin any zum Zurückspiegeln.
Beachten Sie, dass any plus Credentials jeder Website erlaubt,
authentifizierte Antworten von diesem Ort zu lesen; dies ist erlaubt und
protokolliert eine Warnung beim Start.
cors_max_age
Syntax: cors_max_age <zeit>;
Standard: — (der Header wird weggelassen)
Kontext: http, server, location, if in location
Wie lange ein Browser das Preflight-Ergebnis zwischenspeichern darf.
cors_max_age 0; ist ein sinnvoller Wert und wird ausgegeben; das Weglassen
der Direktive lässt den Header weg.
cors_preflight
Syntax: cors_preflight on | off;
Standard: cors_preflight on;
Kontext: http, server, location, if in location
Ob passende Preflight-Anfragen intern beantwortet werden sollen. Schalten Sie
es aus, wenn Ihre Anwendung OPTIONS selbst implementiert und Sie nur die
Antwort-Header hinzugefügt haben möchten.
Eine Preflight-Anfrage wird nur dann kurzgeschlossen, wenn sie wirklich eine
ist — ein OPTIONS mit sowohl Origin als auch
Access-Control-Request-Method — und der Ursprung übereinstimmt. Alles
andere fällt unverändert durch, sodass WebDAV und OPTIONS auf
Anwendungsebene weiterhin funktionieren, und eine Preflight-Anfrage von einem
nicht erlaubten Ursprung erhält einfach kein Access-Control-Allow-Origin,
was den Browser dazu bringt, sie abzulehnen.
Da der Handler in der Preaccess-Phase läuft, wird eine Preflight-Anfrage
beantwortet, bevor auth_basic, auth_request und deny die Chance haben,
sie abzulehnen. Das ist beabsichtigt: Browser senden niemals Credentials bei
einer Preflight-Anfrage, sodass jede davor geschaltete Authentifizierung CORS
vollständig brechen würde. Tatsächliche Anfragen an denselben Ort werden
weiterhin normal authentifiziert.
cors_vary
Syntax: cors_vary on | off;
Standard: cors_vary on;
Kontext: http, server, location, if in location
Ob Vary: Origin ausgegeben werden soll, wenn die Antwort vom Ursprung der
Anfrage abhängt.
Lassen Sie dies aktiviert. Es wird immer dann ausgegeben, wenn die Richtlinie
ursprungsabhängig ist — einschließlich wenn der Ursprung nicht übereinstimmte
und wenn die Anfrage gar kein Origin enthielt, weil eine zwischengespeicherte
Kopie dieser Antwort niemals für eine Anfrage wiedergegeben werden darf, deren
Ursprung andere Header erzeugt hätte. Es wird bewusst nicht für ein
statisches cors_origin * ausgegeben, das für alle gleich ist und nicht
variiert.
Schalten Sie es nur aus, wenn Sie wissen, dass kein gemeinsamer Cache vor
diesem Ort liegt, oder Ihr CDN bereits auf Origin schlüsselt.
Hinweise
- Ein bereits vorhandenes
Varyauf der Antwort wird erweitert, nie ersetzt: Ein Upstream, derVary: Accept-Languagesendet, ergibtVary: Accept-Language, Origin, und mehrereVary-Zeilen vom Upstream werden zu einer zusammengefaltet. EinVary: *bleibt unverändert, da es laut RFC 9110 bereits alles umfasst. - Zwei Dinge fügen ihr
Varynach diesem Modul hinzu und kommen daher als separate Feldzeile an, anstatt eingefaltet zu werden: einadd_header Vary ...im selbenlocationundgzip_vary on'sVary: Accept-Encoding. MehrereVary-Feldzeilen bedeuten genau dasselbe wie eine kombinierte Zeile (RFC 9110 §5.3), und jeder Cache verarbeitet das, also ist dies korrekt — nur nicht aufgeräumt. Laden Sienginx-module-compression-vary, wenn Sie alles in einer Zeile zusammengefaltet haben möchten. - Setzen Sie CORS-Header nicht zusätzlich mit
add_headerim selbenlocation. Dieses Modul ersetzt jedesAccess-Control-Allow-Origin, das es findet — zwei davon sind ein harter Fehler in jedem Browser —, aber die anderen Header würden dupliziert. - Header werden bei 304- und 206-Antworten sowie bei Fehlern ausgegeben.
- Subrequests werden übersprungen, entsprechend dem Verhalten von
add_header.