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:
Sean McArthur
2017-01-19 12:53:08 -08:00
parent 7d400398ab
commit 8e790831c1
3 changed files with 146 additions and 35 deletions

View File

@@ -1,5 +1,5 @@
use header::{Header, Raw};
use std::fmt::{self, Display};
use std::fmt;
use std::str::from_utf8;
@@ -90,14 +90,26 @@ impl Header for SetCookie {
Err(::Error::Header)
}
}
fn fmt_header(&self, _f: &mut fmt::Formatter) -> fmt::Result {
panic!("SetCookie cannot be used with fmt_header, must use fmt_multi_header");
}
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, cookie) in self.0.iter().enumerate() {
if i != 0 {
try!(f.write_str("\r\nSet-Cookie: "));
}
try!(Display::fmt(cookie, f));
fn fmt_multi_header(&self, f: &mut ::header::MultilineFormatter) -> fmt::Result {
for cookie in &self.0 {
try!(f.fmt_line(cookie));
}
Ok(())
}
}
#[test]
fn test_set_cookie_fmt() {
use ::header::Headers;
let mut headers = Headers::new();
headers.set(SetCookie(vec![
"foo=bar".into(),
"baz=quux".into(),
]));
assert_eq!(headers.to_string(), "Set-Cookie: foo=bar\r\nSet-Cookie: baz=quux\r\n");
}