fix(header): security fix for header values that include newlines
Newlines in header values will now be replaced with spaces when being written to strings or to sockets. This prevents headers that are built from user data to smuggle unintended headers or requests/responses. Thanks to @skylerberg for the responsible reporting of this issue, and helping to keep us all safe! BREAKING CHANGE: This technically will cause code that a calls `SetCookie.fmt_header` to panic, as it is no longer to properly write that method. Most people should not be doing this at all, and all other ways of printing headers should work just fine. The breaking change must occur in a patch version because of the security nature of the fix.
This commit is contained in:
@@ -4,7 +4,7 @@ use std::fmt;
|
||||
use std::str::from_utf8;
|
||||
|
||||
use super::cell::{OptCell, PtrMapCell};
|
||||
use header::{Header, Raw};
|
||||
use header::{Header, MultilineFormatter, Raw};
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -90,6 +90,29 @@ impl Item {
|
||||
None => parse::<H>(self.raw.as_ref().expect("item.raw must exist")).ok()
|
||||
}.map(|typed| unsafe { typed.downcast_unchecked() })
|
||||
}
|
||||
|
||||
pub fn write_h1(&self, f: &mut MultilineFormatter) -> fmt::Result {
|
||||
match *self.raw {
|
||||
Some(ref raw) => {
|
||||
for part in raw.iter() {
|
||||
match from_utf8(&part[..]) {
|
||||
Ok(s) => {
|
||||
try!(f.fmt_line(&s));
|
||||
},
|
||||
Err(_) => {
|
||||
error!("raw header value is not utf8, value={:?}", part);
|
||||
return Err(fmt::Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
None => {
|
||||
let typed = unsafe { self.typed.one() };
|
||||
typed.fmt_multi_header(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -99,24 +122,3 @@ fn parse<H: Header>(raw: &Raw) -> ::Result<Box<Header + Send + Sync>> {
|
||||
h
|
||||
})
|
||||
}
|
||||
|
||||
impl fmt::Display for Item {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self.raw {
|
||||
Some(ref raw) => {
|
||||
for part in raw.iter() {
|
||||
match from_utf8(&part[..]) {
|
||||
Ok(s) => try!(f.write_str(s)),
|
||||
Err(e) => {
|
||||
error!("raw header value is not utf8. header={:?}, error={:?}",
|
||||
part, e);
|
||||
return Err(fmt::Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
None => fmt::Display::fmt(&unsafe { self.typed.one() }, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user