diff --git a/src/http/mod.rs b/src/http/mod.rs index 161cc10..9d1b3a3 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -18,7 +18,7 @@ use bytes::Bytes; #[cfg(test)] use flate2::read::GzDecoder; use http::header::{ - ACCEPT, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, COOKIE, HeaderMap, + ACCEPT, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, COOKIE, HOST, HeaderMap, HeaderName, HeaderValue, LOCATION, PROXY_AUTHORIZATION, RANGE, RETRY_AFTER, TRANSFER_ENCODING, USER_AGENT, WWW_AUTHENTICATE, }; diff --git a/src/http/retry.rs b/src/http/retry.rs index a97df1e..bfc0979 100644 --- a/src/http/retry.rs +++ b/src/http/retry.rs @@ -166,6 +166,7 @@ pub(super) fn same_origin(a: &Url, b: &Url) -> bool { pub(super) fn strip_cross_origin_sensitive_headers(headers: &mut HeaderMap) { headers.remove(AUTHORIZATION); headers.remove(COOKIE); + headers.remove(HOST); headers.remove(PROXY_AUTHORIZATION); } diff --git a/tests/http.rs b/tests/http.rs index 9fbdd7a..543b254 100644 --- a/tests/http.rs +++ b/tests/http.rs @@ -623,6 +623,7 @@ fn cross_origin_redirect_strips_explicit_sensitive_headers() { if !req.header("authorization").is_empty() || !req.header("cookie").is_empty() || !req.header("proxy-authorization").is_empty() + || req.header("host") == "tenant-a.example" { return TestResponse::status(400, "Bad Request", "sensitive header leaked"); } @@ -641,6 +642,8 @@ fn cross_origin_redirect_strips_explicit_sensitive_headers() { "Cookie: sid=secret", "--header", "Proxy-Authorization: proxy-secret", + "--header", + "Host: tenant-a.example", ]); assert_exit(&res, 0); assert_eq!(res.stdout, "safe"); @@ -650,6 +653,30 @@ fn cross_origin_redirect_strips_explicit_sensitive_headers() { assert!(requests[0].header("authorization").is_empty()); assert!(requests[0].header("cookie").is_empty()); assert!(requests[0].header("proxy-authorization").is_empty()); + assert_ne!(requests[0].header("host"), "tenant-a.example"); + assert!(!requests[0].header("host").is_empty()); +} + +#[test] +fn same_origin_redirect_preserves_explicit_host_header() { + let server = TestServer::start(|req| match req.path.as_str() { + "/start" => TestResponse::status(302, "Found", "").header("Location", "/final"), + "/final" if req.header("host") == "tenant-a.example" => TestResponse::ok("preserved"), + _ => TestResponse::status(400, "Bad Request", "host header changed"), + }); + + let res = run_fetch(&[ + &format!("{}/start", server.url), + "--header", + "Host: tenant-a.example", + ]); + assert_exit(&res, 0); + assert_eq!(res.stdout, "preserved"); + + let requests = server.requests(); + assert_eq!(requests.len(), 2); + assert_eq!(requests[0].header("host"), "tenant-a.example"); + assert_eq!(requests[1].header("host"), "tenant-a.example"); } #[test]