Cross-Origin-Kontrolle
CORS (Cross-Origin Resource Sharing) ist ein Mechanismus, der es Browsern ermöglicht, Anfragen an serverübergreifende Server zu stellen und so die Beschränkungen der Browser-Same-Origin-Policy zu umgehen.
Was ist die Same-Origin-Policy?
Die Same-Origin-Policy ist eine Sicherheitsfunktion von Browsern, die einschränkt, wie Dokumente oder Skripte von einem Ursprung mit Ressourcen eines anderen Ursprungs interagieren können. "Same Origin" bedeutet, dass Protokoll, Domain und Portnummer identisch sind.
Warum wird CORS benötigt?
CORS-Unterstützung ist erforderlich, wenn eine Frontend-Anwendung auf APIs eines anderen Ursprungs zugreifen muss. Beispiel:
- Die Frontend-Anwendung ist unter
https://frontend.com bereitgestellt
- Der API-Dienst ist unter
https://api.backend.com bereitgestellt
Ohne CORS verhindert der Browser, dass die Frontend-Anwendung auf den API-Dienst zugreift.
Wie CORS funktioniert
CORS implementiert die serverübergreifende Zugriffskontrolle durch eine Reihe von HTTP-Headern:
- Einfache Anfragen: Werden direkt gesendet, wobei der Server über Antwort-Header steuert, ob der Zugriff erlaubt ist.
- Preflight-Anfragen: Der Browser sendet zuerst eine OPTIONS-Anfrage, um den Server zu fragen, ob serverübergreifender Zugriff erlaubt ist, und sendet die eigentliche Anfrage erst nach Erhalt der Erlaubnis.
Da der Browser Preflight-Anfragen mit Method::OPTIONS sendet, ist es notwendig, solche Anfragen zu behandeln. Das CORS-Middleware muss zum Service hinzugefügt werden.
Verwendung von CORS in Salvo
Salvo bietet ein integriertes CORS-Middleware, das einfach konfiguriert und verwendet werden kann. Hier ist ein Beispielcodeausschnitt:
Warning
Hinweis: Das .hoop(cors)-Middleware wird auf den Service angewendet, nicht auf den Router. Dies stellt sicher, dass OPTIONS-Preflight-Anfragen automatisch behandelt werden.
let cors = Cors::new()
.allow_origin(["http://127.0.0.1:8698", "http://localhost:8698"])
.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
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:8698
// - Allow specific HTTP methods
// - Allow authorization header
let cors = Cors::new()
.allow_origin(["http://127.0.0.1:8698", "http://localhost:8698"])
.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 8698
let acceptor = TcpListener::new("0.0.0.0:8698").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>
"#;
[package]
name = "example-cors"
version.workspace = true
edition.workspace = true
publish.workspace = true
rust-version.workspace = true
[dependencies]
salvo = { workspace = true, features = ["cors"] }
tokio = { workspace = true, features = ["macros"] }
tracing.workspace = true
tracing-subscriber.workspace = true
Hauptkonfigurationsoptionen
Das CORS-Middleware bietet verschiedene Konfigurationsoptionen:
- Erlaubte Ursprünge: Steuert, welche Domänen auf Ressourcen zugreifen können.
- Erlaubte Methoden: Gibt erlaubte HTTP-Methoden an (GET, POST, etc.).
- Erlaubte Header: Gibt erlaubte Anfrage-Header an.
- Verfügbar gemachte Header: Gibt an, welche Antwort-Header vom Client abgerufen werden können.
- Anmeldedaten erlauben: Bestimmt, ob Anfragen Anmeldedaten wie Cookies enthalten dürfen.
- Preflight-Anfrage-Cache-Zeit: Die Cache-Dauer für Preflight-Anfrageergebnisse.
Durch angemessene Konfiguration von CORS können Sie sowohl Sicherheit als auch die Fähigkeit gewährleisten, serverübergreifende Zugriffsanforderungen zu erfüllen.