CORS Cross Origin Erklaerung
CORS: Cross-Origin Resource Sharing verstehen
CORS ist eine der häufigsten Fehlerquellen bei Web-Entwicklung. Dieser Guide erklärt, was CORS ist, warum es existiert und wie Sie es richtig konfigurieren.
Was ist CORS?
CORS (Cross-Origin Resource Sharing) ist ein Sicherheitsmechanismus im Browser. Er verhindert, dass JavaScript von einer Website auf Ressourcen einer anderen Website zugreift.
Same-Origin Policy
Browser blockieren standardmäßig Anfragen an andere "Origins". Ein Origin besteht aus:
- Protokoll: http vs https
- Domain: example.com vs api.example.com
- Port: :80 vs :8080
| Von | Nach | Erlaubt? |
|---|---|---|
| https://example.com | https://example.com/api | ✅ Ja (gleicher Origin) |
| https://example.com | https://api.example.com | ❌ Nein (andere Subdomain) |
| https://example.com | http://example.com | ❌ Nein (anderes Protokoll) |
| https://example.com | https://example.com:8080 | ❌ Nein (anderer Port) |
Der typische CORS-Fehler
Access to fetch at 'https://api.example.com/data' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Wie CORS funktioniert
Einfache Anfragen
GET, HEAD, POST mit bestimmten Content-Types gehen direkt durch:
// Browser sendet automatisch Origin-Header GET /api/data HTTP/1.1 Host: api.example.com Origin: https://example.com // Server muss antworten mit: HTTP/1.1 200 OK Access-Control-Allow-Origin: https://example.com
Preflight-Anfragen
Bei komplexeren Anfragen sendet der Browser erst eine OPTIONS-Anfrage:
// 1. Browser sendet Preflight OPTIONS /api/data HTTP/1.1 Host: api.example.com Origin: https://example.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: Content-Type, Authorization // 2. Server erlaubt (oder nicht) HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://example.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 86400 // 3. Browser sendet eigentliche Anfrage PUT /api/data HTTP/1.1 ...
CORS-Header im Detail
| Header | Beschreibung |
|---|---|
Access-Control-Allow-Origin |
Erlaubte Origin(s) - * für alle |
Access-Control-Allow-Methods |
Erlaubte HTTP-Methoden |
Access-Control-Allow-Headers |
Erlaubte Request-Header |
Access-Control-Allow-Credentials |
Cookies/Auth erlauben (true/false) |
Access-Control-Max-Age |
Preflight-Cache in Sekunden |
Access-Control-Expose-Headers |
Header die JS lesen darf |
CORS in verschiedenen Umgebungen
Node.js/Express
const cors = require('cors');
// Alle Origins erlauben (nur Entwicklung!)
app.use(cors());
// Spezifische Origin
app.use(cors({
origin: 'https://example.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
// Mehrere Origins
const allowedOrigins = ['https://example.com', 'https://app.example.com'];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
}
}));
PHP
<?php
// Alle Origins (nur Entwicklung!)
header('Access-Control-Allow-Origin: *');
// Spezifische Origin
header('Access-Control-Allow-Origin: https://example.com');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Credentials: true');
// Preflight abfangen
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
Nginx
location /api/ {
# Spezifische Origin
add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
# Preflight
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://backend;
}
Häufige Fehler
Access-Control-Allow-Origin: *mit Credentials- OPTIONS-Anfragen nicht behandeln
- Header nur bei erfolgreichen Responses
- Wildcard in Produktion nutzen
Credentials mit Wildcard
// FALSCH - funktioniert nicht! Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true // RICHTIG - spezifische Origin Access-Control-Allow-Origin: https://example.com Access-Control-Allow-Credentials: true
Entwicklungs-Workarounds
Proxy in Vite/React
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
}