fix HRS vuln when first CL header is 0

This commit is contained in:
Rob Ede 2022-06-27 03:37:55 +01:00
parent c6eba2da9b
commit 399c5ea426
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
1 changed files with 22 additions and 8 deletions

View File

@ -88,20 +88,22 @@ pub(crate) trait MessageType: Sized {
} }
header::CONTENT_LENGTH => match value.to_str() { header::CONTENT_LENGTH => match value.to_str() {
Ok(s) if s.trim().starts_with('+') => { Ok(val) if val.trim().starts_with('+') => {
debug!("illegal Content-Length: {:?}", s); debug!("illegal Content-Length: {:?}", val);
return Err(ParseError::Header); return Err(ParseError::Header);
} }
Ok(s) => {
if let Ok(len) = s.parse::<u64>() { Ok(val) => {
if len != 0 { if let Ok(len) = val.trim().parse::<u64>() {
// accept 0 lengths here and remove them later in this method after
// all headers have been processed
content_length = Some(len); content_length = Some(len);
}
} else { } else {
debug!("illegal Content-Length: {:?}", s); debug!("illegal Content-Length: {:?}", val);
return Err(ParseError::Header); return Err(ParseError::Header);
} }
} }
Err(_) => { Err(_) => {
debug!("illegal Content-Length: {:?}", value); debug!("illegal Content-Length: {:?}", value);
return Err(ParseError::Header); return Err(ParseError::Header);
@ -130,6 +132,7 @@ pub(crate) trait MessageType: Sized {
return Err(ParseError::Header); return Err(ParseError::Header);
} }
} }
// connection keep-alive state // connection keep-alive state
header::CONNECTION => { header::CONNECTION => {
ka = if let Ok(conn) = value.to_str().map(str::trim) { ka = if let Ok(conn) = value.to_str().map(str::trim) {
@ -146,6 +149,7 @@ pub(crate) trait MessageType: Sized {
None None
}; };
} }
header::UPGRADE => { header::UPGRADE => {
if let Ok(val) = value.to_str().map(str::trim) { if let Ok(val) = value.to_str().map(str::trim) {
if val.eq_ignore_ascii_case("websocket") { if val.eq_ignore_ascii_case("websocket") {
@ -153,23 +157,33 @@ pub(crate) trait MessageType: Sized {
} }
} }
} }
header::EXPECT => { header::EXPECT => {
let bytes = value.as_bytes(); let bytes = value.as_bytes();
if bytes.len() >= 4 && &bytes[0..4] == b"100-" { if bytes.len() >= 4 && &bytes[0..4] == b"100-" {
expect = true; expect = true;
} }
} }
_ => {} _ => {}
} }
headers.append(name, value); headers.append(name, value);
} }
} }
self.set_connection_type(ka); self.set_connection_type(ka);
if expect { if expect {
self.set_expect() self.set_expect()
} }
// Remove CL value if 0 now that all headers are processed. Protects against some request
// smuggling attacks. See https://github.com/actix/actix-web/issues/2767.
if matches!(content_length, Some(0)) {
content_length = None;
}
// https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3 // https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3
if chunked { if chunked {
// Chunked encoding // Chunked encoding