Cross-Origin-Ressourcenfreigabe (CORS)
CORS (Cross-Origin Resource Sharing) ist ein Mechanismus, der es Browsern ermöglicht, Anfragen an Server unterschiedlicher Herkunft zu senden und somit die Same-Origin-Policy des Browsers zu umgehen.
Was ist die Same-Origin-Policy?
Die Same-Origin-Policy ist eine Sicherheitsfunktion des Browsers, die einschränkt, wie Dokumente oder Skripte, die von einer Quelle geladen wurden, mit Ressourcen einer anderen Quelle interagieren können. "Gleiche Herkunft" bedeutet dabei identisches Protokoll, Domain und Portnummer.
Warum wird CORS benötigt?
Wenn eine Frontend-Anwendung auf APIs unterschiedlicher Herkunft zugreifen muss, ist CORS erforderlich. Beispiel:
- Frontend-Anwendung bereitgestellt unter
https://frontend.com
- API-Service bereitgestellt unter
https://api.backend.com
Ohne CORS würde der Browser den Zugriff der Frontend-Anwendung auf den API-Service blockieren.
Funktionsweise von CORS
CORS steuert den Cross-Origin-Zugriff über eine Reihe von HTTP-Headern:
- Einfache Anfragen: Werden direkt gesendet, der Server kontrolliert über Antwort-Header, ob sie erlaubt sind
- Preflight-Anfragen: Der Browser sendet zunächst eine OPTIONS-Anfrage, um die Erlaubnis für Cross-Origin-Zugriff abzufragen, bevor die eigentliche Anfrage gesendet wird
Da der Browser Preflight-Anfragen mit Method::OPTIONS
sendet, muss die Behandlung solcher Anfragen implementiert werden. Dazu muss das CORS-Middleware dem Service
hinzugefügt werden.
Verwendung von CORS in Salvo
Salvo bietet ein integriertes CORS-Middleware, das einfach konfiguriert und verwendet werden kann. Hier ein Beispielcode:
WARNING
Hinweis. Das .hoop(cors)-Middleware wirkt auf den Service
, nicht auf den Router
. Dadurch werden OPTIONS-Preflight-Anfragen automatisch behandelt.
let cors = Cors::new()
.allow_origin(["http://127.0.0.1:5800", "http://localhost:5800"])
.allow_methods(vec![Method::GET, Method::POST, Method::DELETE])
.allow_headers("authorization")
.into_handler();
// Backend-Router mit CORS-Schutz einrichten
let router = Router::with_path("hello").post(hello);
let service = Service::new(router).hoop(cors);
Beispielcode
cors/src/main.rs
use salvo::cors::Cors;
use salvo::http::Method;
use salvo::prelude::*;
#[tokio::main]
async fn main() {
// Initialize logging system
tracing_subscriber::fmt().init();
// Start both backend and frontend servers concurrently
tokio::join!(backend_server(), frontend_server());
}
async fn backend_server() {
// Handler that returns a simple message for CORS demonstration
#[handler]
async fn hello() -> &'static str {
"hello, I am content from remote server."
}
// Configure CORS middleware with specific settings:
// - Allow requests from localhost:5800
// - Allow specific HTTP methods
// - Allow authorization header
let cors = Cors::new()
.allow_origin(["http://127.0.0.1:5800", "http://localhost:5800"])
.allow_methods(vec![Method::GET, Method::POST, Method::DELETE])
.allow_headers("authorization")
.into_handler();
// Set up backend router with CORS protection
let router = Router::with_path("hello").post(hello);
let service = Service::new(router).hoop(cors);
// Start backend server on port 5600
let acceptor = TcpListener::new("0.0.0.0:5600").bind().await;
Server::new(acceptor).serve(service).await;
}
async fn frontend_server() {
// Handler that serves the HTML page with CORS test
#[handler]
async fn index() -> Text<&'static str> {
Text::Html(HTML_DATA)
}
// Set up frontend router to serve the test page
let router = Router::new().get(index);
// Start frontend server on port 5800
let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
Server::new(acceptor).serve(router).await;
}
// HTML template with JavaScript code to test CORS
// Contains a button that triggers a POST request to the backend server
const HTML_DATA: &str = r#"
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Salvo Cors</title>
</head>
<body>
<button id="btn">Load Content</button>
<div id="content"></div>
<script>
document.getElementById("btn").addEventListener("click", function() {
fetch("http://127.0.0.1:5600/hello", {method: "POST", headers: {authorization: "abcdef"}}).then(function(response) {
return response.text();
}).then(function(data) {
document.getElementById("content").innerHTML = data;
});
});
</script>
</body>
</html>
"#;
Hauptkonfigurationsoptionen
Das CORS-Middleware bietet verschiedene Konfigurationsmöglichkeiten:
- Erlaubte Ursprünge: Steuert, welche Domänen auf Ressourcen zugreifen dürfen
- Erlaubte Methoden: Legt die erlaubten HTTP-Methoden fest (GET, POST etc.)
- Erlaubte Header: Spezifiziert die erlaubten Anfrage-Header
- Verfügbar gemachte Header: Legt fest, welche Antwort-Header für Clients sichtbar sein sollen
- Erlaubte Credentials: Ob Anfragen Credentials wie Cookies enthalten dürfen
- Preflight-Cache-Zeit: Wie lange das Ergebnis von Preflight-Anfragen zwischengespeichert wird
Durch angemessene CORS-Konfiguration können sowohl Sicherheit gewährleistet als auch Cross-Origin-Zugriffsanforderungen erfüllt werden.