From 623b87397a569729c4bcabae747823c5668cce94 Mon Sep 17 00:00:00 2001 From: Ben Stern Date: Sat, 2 Jan 2021 15:18:30 -0500 Subject: [PATCH 1/4] Fix RUSTSEC-2020-0031 --- src/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.rs b/src/common.rs index 94ffd6612..536820899 100644 --- a/src/common.rs +++ b/src/common.rs @@ -239,7 +239,7 @@ impl FromStr for HeaderField { type Err = (); fn from_str(s: &str) -> Result { - AsciiString::from_ascii(s.trim()) + AsciiString::from_ascii(s) .map(HeaderField) .map_err(|_| ()) } From 952439bc5e9011e5778b16dbbd29e259b925e3c2 Mon Sep 17 00:00:00 2001 From: Ben Stern Date: Thu, 7 Jan 2021 22:11:23 -0500 Subject: [PATCH 2/4] add test --- src/common.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/common.rs b/src/common.rs index 536820899..9b4da03b6 100644 --- a/src/common.rs +++ b/src/common.rs @@ -212,7 +212,7 @@ impl Display for Header { /// Field of a header (eg. `Content-Type`, `Content-Length`, etc.) /// -/// Comparaison between two `HeaderField`s ignores case. +/// Comparison between two `HeaderField`s ignores case. #[derive(Debug, Clone)] pub struct HeaderField(AsciiString); @@ -461,4 +461,13 @@ mod test { assert!(header.field.equiv(&"time")); assert!(header.value.as_str() == "20: 34"); } + + // This tests reslstance to RUSTSEC-2020-0031: "HTTP Request smuggling + // through malformed Transfer Encoding headers" + // (https://rustsec.org/advisories/RUSTSEC-2020-0031.html). + #[test] + fn test_strict_headers() { + let smuggled = "Transfer-Encoding : chunked".parse::
().unwrap(); + assert!(!smuggled.field.equiv("Transfer-Encoding")); + } } From 46a14ca45be8ef7b9295f3321d1d4902e56a77f0 Mon Sep 17 00:00:00 2001 From: Ben Stern Date: Fri, 8 Jan 2021 19:24:21 -0500 Subject: [PATCH 3/4] Header fields can't contain whitespace. --- src/common.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/common.rs b/src/common.rs index 9b4da03b6..b8050b94e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -239,9 +239,13 @@ impl FromStr for HeaderField { type Err = (); fn from_str(s: &str) -> Result { - AsciiString::from_ascii(s) - .map(HeaderField) - .map_err(|_| ()) + if s.contains(char::is_whitespace) { + Err(()) + } else { + AsciiString::from_ascii(s) + .map(HeaderField) + .map_err(|_| ()) + } } } @@ -467,7 +471,12 @@ mod test { // (https://rustsec.org/advisories/RUSTSEC-2020-0031.html). #[test] fn test_strict_headers() { - let smuggled = "Transfer-Encoding : chunked".parse::
().unwrap(); - assert!(!smuggled.field.equiv("Transfer-Encoding")); + assert!("Transfer-Encoding : chunked".parse::
().is_err()); + assert!(" Transfer-Encoding: chunked".parse::
().is_err()); + assert!("Transfer Encoding: chunked".parse::
().is_err()); + assert!(" Transfer\tEncoding : chunked".parse::
().is_err()); + assert!("Transfer-Encoding: chunked".parse::
().is_ok()); + assert!("Transfer-Encoding: chunked ".parse::
().is_ok()); + assert!("Transfer-Encoding: chunked ".parse::
().is_ok()); } } From cbe07c3cefadabe678b7b38fbed814f715ad71b7 Mon Sep 17 00:00:00 2001 From: Ben Stern Date: Sat, 9 Jan 2021 15:22:22 -0500 Subject: [PATCH 4/4] Add test suggested (and written) by @rawler --- tests/input-tests.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/input-tests.rs b/tests/input-tests.rs index 85d59db8a..78db98137 100644 --- a/tests/input-tests.rs +++ b/tests/input-tests.rs @@ -81,3 +81,15 @@ fn unsupported_expect_header() { client.read_to_string(&mut content).unwrap(); assert!(&content[9..].starts_with("417")); // 417 status code } + +#[test] +fn invalid_header_name() { + let mut client = support::new_client_to_hello_world_server(); + + // note the space hidden in the Content-Length, which is invalid + (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\nContent-Type: text/plain; charset=utf8\r\nContent-Length : 5\r\n\r\nhello")).unwrap(); + + let mut content = String::new(); + client.read_to_string(&mut content).unwrap(); + assert!(&content[9..].starts_with("400 Bad Request")); // 400 status code +}