From dac619b2628826d5af935b715f02f04aa8335056 Mon Sep 17 00:00:00 2001 From: Philippe Vienne Date: Sun, 13 Sep 2026 10:23:08 +0200 Subject: [PATCH] =?UTF-8?q?fix(tsa):=20restreint=20vraiment=20le=20CORS=20?= =?UTF-8?q?=C3=A0=20l'origine=20configur=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit allow_origin(HeaderValue) (AllowOrigin::exact) renvoyait Access-Control-Allow-Origin: sur TOUTE requête, quelle que soit l'origine réelle de l'appelant — pas une exploitation directe (le navigateur compare toujours l'en-tête à sa propre origine avant d'autoriser la lecture), mais une fuite de configuration et pas la vraie restriction par origine documentée. AllowOrigin::list ne reflète l'en-tête que si l'Origin de la requête correspond exactement, et l'omet sinon. Ajoute le test qui aurait dû l'attraper. --- crates/oe-httpapi/src/lib.rs | 6 +++++- crates/oe-httpapi/tests/end_to_end.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/oe-httpapi/src/lib.rs b/crates/oe-httpapi/src/lib.rs index ddcbb42..6ac0b7a 100644 --- a/crates/oe-httpapi/src/lib.rs +++ b/crates/oe-httpapi/src/lib.rs @@ -64,9 +64,13 @@ pub fn router(opts: Options) -> Router { .layer(tower_http::trace::TraceLayer::new_for_http()); if let Some(origin) = opts.cors_allowed_origin.as_deref() { if let Ok(origin) = axum::http::HeaderValue::from_str(origin) { + // `allow_origin(HeaderValue)` (AllowOrigin::exact) renverrait cette + // valeur sur TOUTE requête, quelle que soit son origine réelle — + // AllowOrigin::list ne la reflète que si l'en-tête Origin de la + // requête correspond exactement, et l'omet sinon. router = router.layer( tower_http::cors::CorsLayer::new() - .allow_origin(origin) + .allow_origin(tower_http::cors::AllowOrigin::list([origin])) .allow_methods([axum::http::Method::GET, axum::http::Method::POST]) .allow_headers([axum::http::header::CONTENT_TYPE]), ); diff --git a/crates/oe-httpapi/tests/end_to_end.rs b/crates/oe-httpapi/tests/end_to_end.rs index 7637aa6..6d8b4f9 100644 --- a/crates/oe-httpapi/tests/end_to_end.rs +++ b/crates/oe-httpapi/tests/end_to_end.rs @@ -212,4 +212,16 @@ async fn cors_header_present_only_when_configured() { resp.headers().get("access-control-allow-origin").unwrap(), "https://demo.open-eidas.eu" ); + + // Une origine différente, elle, ne doit PAS recevoir l'en-tête : sinon + // `AllowOrigin::exact` renverrait cette même valeur à n'importe qui + // (fuite d'information sur la configuration, pas une vraie restriction + // par origine — voir la revue du commit qui a introduit ce test). + let resp = reqwest::Client::new() + .get(format!("http://{addr}/api/v1/policy")) + .header("Origin", "https://evil.example") + .send() + .await + .unwrap(); + assert!(resp.headers().get("access-control-allow-origin").is_none()); }