In diesem Artikel erfahren Sie, wie Sie CORS (Cross-Origin Resource Sharing) mit HTTPOnly-Cookies aktivieren, um unsere Zugriffstoken zu sichern.
Heutzutage werden Backend-Server und Frontend-Clients auf verschiedenen Domänen bereitgestellt. Daher muss der Server CORS aktivieren, damit Clients über Browser mit dem Server kommunizieren können.
Außerdem implementieren Server für eine bessere Skalierbarkeit eine zustandslose Authentifizierung. Token werden auf der Client-Seite gespeichert und verwaltet, aber nicht auf der Server-Seite wie bei einer Sitzung. Aus Sicherheitsgründen ist es besser, Token in HTTPOnly-Cookies zu speichern.
Why are Cross-Origin requests blocked?
Nehmen wir an, dass unsere Frontend-Anwendung bereitgestellt wird bei https://app.geekflare.com
. Ein Skript geladen in https://app.geekflare.com
kann nur Ressourcen gleichen Ursprungs anfordern.
Immer wenn wir versuchen, eine Cross-Origin-Anfrage an eine andere Domain zu senden https://api.geekflare.com
oder ein anderer Port https://app.geekflare.com:3000
oder ein anderes Schema http://app.geekflare.com
, wird die Cross-Origin-Anfrage vom Browser blockiert.
Aber warum wird die gleiche Anfrage, die vom Browser blockiert wird, von jedem Backend-Server mit curl-Anfrage gesendet oder mit Tools wie dem Postboten ohne CORS-Problem gesendet. Es dient eigentlich der Sicherheit, um Benutzer vor Angriffen wie CSRF (Cross-Site Request Forgery) zu schützen.
Nehmen wir ein Beispiel: Angenommen, ein Benutzer hat sich in seinem Browser mit seinem eigenen PayPal-Konto angemeldet. Wenn wir eine Cross-Origin-Anfrage senden können an paypal.com
von einem Skript, das auf einer anderen Domain geladen wurde malicious.com
ohne CORS-Fehler/Blockierung, wie wir die Same-Origin-Anfrage senden.
Angreifer können ihre bösartige Seite einfach senden https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account
indem Sie es in eine Kurz-URL umwandeln, um die tatsächliche URL auszublenden. Wenn der Benutzer auf einen schädlichen Link klickt, wird das Skript in die Domäne geladen malicious.com
wird eine ursprungsübergreifende Anfrage an PayPal senden, um den Benutzerbetrag auf das PayPal-Konto des Angreifers zu überweisen, wird ausgeführt. Alle Benutzer, die sich bei ihrem PayPal-Konto angemeldet und auf diesen schädlichen Link geklickt haben, verlieren ihr Geld. Jeder kann leicht Geld stehlen, ohne dass ein Benutzerwissen über ein PayPal-Konto vorhanden ist.
Aus dem oben genannten Grund blockieren Browser alle ursprungsübergreifenden Anfragen.
What is CORS(Cross-Origin Resource Sharing)?
CORS ist ein Header-basierter Sicherheitsmechanismus, der vom Server verwendet wird, um den Browser anzuweisen, eine ursprungsübergreifende Anfrage von vertrauenswürdigen Domänen zu senden.
Der mit CORS-Headern aktivierte Server wird verwendet, um zu verhindern, dass ursprungsübergreifende Anfragen von Browsern blockiert werden.
Wie funktioniert CORS?
Da der Server seine vertrauenswürdige Domäne bereits in seiner CORS-Konfiguration definiert hat. Wenn wir eine Anfrage an den Server senden, teilt die Antwort dem Browser mit, dass die angeforderte Domain im Header vertrauenswürdig ist oder nicht.
Es gibt zwei Arten von CORS-Anfragen:
- Einfache Anfrage
- Preflight-Anfrage
Einfache Anfrage:
- Der Browser sendet die Anfrage an eine Cross-Origin-Domain mit Herkunft (https://app.geekflare.com).
- Der Server schickt die entsprechende Antwort zurück mit erlaubte Methoden und erlaubte Herkunft.
- Nach Erhalt der Anfrage überprüft der Browser den gesendeten Ursprungsheaderwert (https://app.geekflare.com) und empfangener Zugriffskontroll-Erlaube-Ursprungswert(https://app.geekflare.com) sind gleich oder Platzhalter(*). Andernfalls wird ein CORS-Fehler ausgegeben.
Preflight-Anfrage:
- Abhängig vom benutzerdefinierten Anfrageparameter der Cross-Origin-Anfrage wie Methoden (PUT, DELETE) oder benutzerdefinierten Headern oder unterschiedlichen Inhaltstypen usw. Der Browser entscheidet, eine Preflight-OPTIONS-Anfrage zu senden, um zu überprüfen, ob die eigentliche Anfrage sicher ist oder nicht.
- Nach Erhalt der Antwort (Statuscode: 204, dh kein Inhalt) sucht der Browser nach dem Zugriffskontrolle-erlauben Parameter für die eigentliche Anfrage. Wenn die Anforderungsparameter vom Server zugelassen werden. Die eigentliche gesendete und empfangene Cross-Origin-Anfrage
If access-control-allow-origin: *
, dann ist die Antwort für alle Ursprünge zulässig. Aber es ist nicht sicher, wenn Sie es nicht brauchen.
How to enable CORS?
Um CORS für eine beliebige Domäne zu aktivieren, aktivieren Sie CORS-Header, um Ursprung, Methoden, benutzerdefinierte Header, Anmeldeinformationen usw. zuzulassen.
Der Browser liest den CORS-Header vom Server und lässt tatsächliche Anfragen vom Client erst nach Überprüfung der Anfrageparameter zu.
- Zugriffskontrolle-Zulassen-Herkunft: Um genaue Domänen anzugeben (https://app.geekflate.com, https://lab.geekflare.com) oder Platzhalter (*)
- Zugriffssteuerung-Zulassen-Methoden: Um die HTTP-Methoden (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) zuzulassen, die nur wir benötigen.
- Access-Control-Allow-Header: Nur bestimmte Header zulassen (Autorisierung, csrf-token)
- Zugangskontrolle-Zulassen-Anmeldeinformationen: Boolescher Wert, der verwendet wird, um ursprungsübergreifende Anmeldeinformationen (Cookies, Autorisierungsheader) zuzulassen.
- Zugangskontrolle-Max.-Alter: Weist den Browser an, die Preflight-Antwort für einige Zeit zwischenzuspeichern.
- Access-Control-Expose-Header: Geben Sie Header an, auf die über ein clientseitiges Skript zugegriffen werden kann.
Um CORS in Apache und Nginx-Webserver zu aktivieren, befolgen Sie dies Lernprogramm.
Aktivieren von CORS in ExpressJS
Nehmen wir ein Beispiel ExpressJS App ohne CORS:
const express = require('express');
const app = express()
app.get('/users', function (req, res, next) {
res.json({msg: 'user get'})
});
app.post('/users', function (req, res, next) {
res.json({msg: 'user create'})
});
app.put('/users', function (req, res, next) {
res.json({msg: 'User update'})
});
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
Im obigen Beispiel haben wir den API-Endpunkt des Benutzers für POST-, PUT- und GET-Methoden aktiviert, jedoch nicht für die DELETE-Methode.
Zur einfachen Aktivierung von CORS in der ExpressJS-App können Sie die Hörner
npm install cors
Zugriffskontrolle-Zulassen-Ursprung
CORS für alle Domänen aktivieren
app.use(cors({
origin: '*'
}));
Aktivieren von CORS für eine einzelne Domäne
app.use(cors({
origin: 'https://app.geekflare.com'
}));
Wenn Sie CORS für den Ursprung zulassen möchten https://app.geekflare.com und https://lab.geekflare.com
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
]
}));
Zugriffssteuerungs-Zulassungsmethoden
Um CORS für alle Methoden zu aktivieren, lassen Sie diese Option im CORS-Modul in ExpressJS weg. Sondern zum Aktivieren bestimmter Methoden (GET, POST, PUT).
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
],
methods: ['GET', 'PUT', 'POST']
}));
Access-Control-Allow-Header
Wird verwendet, um zuzulassen, dass andere Header als Standard-Header mit tatsächlichen Anforderungen gesendet werden.
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
],
methods: ['GET', 'PUT', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token']
}));
Zugangskontrolle-Zulassen-Anmeldeinformationen
Lassen Sie dies weg, wenn Sie dem Browser nicht mitteilen möchten, dass er Anmeldeinformationen auf Anfrage auch auf zulässt withCredentials ist auf true gesetzt.
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
],
methods: ['GET', 'PUT', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
credentials: true
}));
Zugangskontrolle-Max.-Alter
Den Browser anweisen, die Preflight-Antwortinformationen für eine bestimmte Sekunde im Cache zwischenzuspeichern. Lassen Sie dies weg, wenn Sie die Antwort nicht zwischenspeichern möchten.
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
],
methods: ['GET', 'PUT', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
credentials: true,
maxAge: 600
}));
Die zwischengespeicherte Preflight-Antwort ist 10 Minuten lang im Browser verfügbar.
Access-Control-Expose-Header
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
],
methods: ['GET', 'PUT', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
credentials: true,
maxAge: 600,
exposedHeaders: ['Content-Range', 'X-Content-Range']
}));
Wenn wir den Platzhalter (*) in ausgesetztKopfzeilen, es wird den Authorization-Header nicht verfügbar machen. Also müssen wir wie unten explizit exponieren
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
],
methods: ['GET', 'PUT', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
credentials: true,
maxAge: 600,
exposedHeaders: ['*', 'Authorization', ]
}));
Das Obige macht auch alle Header und den Autorisierungs-Header verfügbar.
What is an HTTP cookie?
Ein Cookie ist ein kleines Datenstück, das der Server an den Client-Browser sendet. Bei späteren Anfragen sendet der Browser bei jeder Anfrage alle Cookies, die sich auf dieselbe Domain beziehen.
Cookie hat ein Attribut, das definiert werden kann, damit ein Cookie je nach Bedarf anders funktioniert.
- Name Name des Cookies.
- Wert: Cookie-Daten bezüglich des Cookie-Namens
- المجال: Cookies werden nur an die definierte Domain gesendet
- Pfad: Cookies, die nur nach dem definierten URL-Präfix-Pfad gesendet werden. Angenommen, wir haben unseren Cookie-Pfad wie path='admin/' definiert. Cookies, die nicht für die URL https://geekflare.com/expire/ gesendet werden, sondern mit dem URL-Präfix https://geekflare.com/admin/ gesendet werden
- Max-Age/Expires (Zahl in Sekunden): Wann sollte das Cookie ablaufen. Eine Lebensdauer des Cookies macht das Cookie nach der angegebenen Zeit ungültig.
- Nur HTTP (Boolesch): Der Back-End-Server kann auf dieses HTTPOnly-Cookie zugreifen, jedoch nicht auf das clientseitige Skript, wenn es wahr ist.
- Sicher(Boolean): Cookies werden nur über eine SSL/TLS-Domain gesendet, wenn sie wahr sind.
- sameSite(string [Streng, Lax, Keine]): Wird verwendet, um Cookies zu aktivieren/einzuschränken, die bei Cross-Site-Anfragen gesendet werden. Um mehr über Cookies zu erfahren
sameSite
sehen DND. Es akzeptiert drei Optionen Strikt, Lax, Keine. Der sichere Cookie-Wert ist für die Cookie-Konfiguration sameSite=None auf "true" gesetzt.
Why HTTPOnly cookie for tokens?
Speichern des vom Server gesendeten Zugriffstokens in einem clientseitigen Speicher wie lokaler Speicher, indizierte DB, und Plätzchen (HTTPOnly nicht auf true gesetzt) sind anfälliger für XSS-Angriff. Angenommen, eine Ihrer Seiten ist für einen XSS-Angriff schwach. Angreifer können im Browser gespeicherte Benutzer-Token missbrauchen.
HTTPOnly-Cookies werden nur vom Server/Backend gesetzt/abgeholt, jedoch nicht auf der Client-Seite.
Clientseitiges Skript, das auf den Zugriff auf dieses HTTPonly-Cookie beschränkt ist. HTTPOnly-Cookies sind also nicht anfällig für XSS-Angriffe und sicherer. Weil nur der Server darauf zugreifen kann.
Enable HTTPOnly cookie in CORS enabled backend
Das Aktivieren von Cookie in CORS erfordert die folgende Konfiguration in der Anwendung/dem Server.
- Setzen Sie den Header Access-Control-Allow-Credentials auf true.
- Access-Control-Allow-Origin und Access-Control-Allow-Header sollten keine Platzhalter (*) sein.
- Das Attribut "sameSite" des Cookies sollte "Keine" sein.
- Um den Wert von sameSite auf none zu aktivieren, setzen Sie den Wert für secure auf true: Aktivieren Sie das Back-End mit SSL/TLS-Zertifikat, damit es im Domänennamen funktioniert.
Sehen wir uns einen Beispielcode an, der ein Zugriffstoken im HTTPOnly-Cookie festlegt, nachdem die Anmeldeinformationen überprüft wurden.
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors({
origin: [
'https://app.geekflare.com',
'https://lab.geekflare.com'
],
methods: ['GET', 'PUT', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
credentials: true,
maxAge: 600,
exposedHeaders: ['*', 'Authorization' ]
}));
app.post('/login', function (req, res, next) {
res.cookie('access_token', access_token, {
expires: new Date(Date.now() + (3600 * 1000 * 24 * 180 * 1)), //second min hour days year
secure: true, // set to true if your using https or samesite is none
httpOnly: true, // backend only
sameSite: 'none' // set to none for cross-request
});
res.json({ msg: 'Login Successfully', access_token });
});
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
});
Sie können CORS- und HTTPOnly-Cookies konfigurieren, indem Sie die obigen vier Schritte in Ihrer Backend-Sprache und Ihrem Webserver implementieren.
Sie können dies verfolgen Lernprogramm für Apache und Nginx zum Aktivieren von CORS, indem Sie die obigen Schritte ausführen.
withCredentials for Cross-Origin request
Anmeldeinformationen (Cookie, Autorisierung) werden standardmäßig mit derselben Ursprungsanforderung gesendet. Für Cross-Origin müssen wir withCredentials auf true setzen.
XMLHttpRequest-API
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.geekflare.com/user', true);
xhr.withCredentials = true;
xhr.send(null);
Fetch API
fetch('http://api.geekflare.com/user', {
credentials: 'include'
});
JQuery Ajax
$.ajax({
url: 'http://api.geekflare.com/user',
xhrFields: {
withCredentials: true
}
});
Axios
axios.defaults.withCredentials = true
Fazit
Ich hoffe, der obige Artikel hilft Ihnen dabei, die Funktionsweise von CORS zu verstehen und CORS für ursprungsübergreifende Anforderungen im Server zu aktivieren. Warum das Speichern von Cookies in HTTPOnly sicher ist und wie mitAnmeldeinformationen, die in Clients für ursprungsübergreifende Anfragen verwendet werden.