Merged revisions 87873 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/py3k

........
  r87873 | r.david.murray | 2011-01-08 21:35:24 -0500 (Sat, 08 Jan 2011) | 12 lines

  #5871: protect against header injection attacks.

  This makes Header.encode throw a HeaderParseError if it winds up
  formatting a header such that a continuation line has no leading
  whitespace and looks like a header.  Since Header accepts values
  containing newlines and preserves them (and this is by design), without
  this fix any program that took user input (say, a subject in a web form)
  and passed it to the email package as a header was vulnerable to header
  injection attacks.  (As far as we know this has never been exploited.)

  Thanks to Jakub Wilk for reporting this vulnerability.
........
This commit is contained in:
R. David Murray 2011-01-09 03:02:04 +00:00
parent c4c52dd23d
commit d97f5ce377
3 changed files with 27 additions and 1 deletions

View file

@ -47,6 +47,10 @@ ecre = re.compile(r'''
# For use with .match()
fcre = re.compile(r'[\041-\176]+:$')
# Find a header embeded in a putative header value. Used to check for
# header injection attack.
_embeded_header = re.compile(r'\n[^ \t]+:')
# Helpers
@ -403,7 +407,11 @@ class Header:
newchunks += self._split(s, charset, targetlen, splitchars)
lastchunk, lastcharset = newchunks[-1]
lastlen = lastcharset.encoded_header_len(lastchunk)
return self._encode_chunks(newchunks, maxlinelen)
value = self._encode_chunks(newchunks, maxlinelen)
if _embeded_header.search(value):
raise HeaderParseError("header value appears to contain "
"an embedded header: {!r}".format(value))
return value

View file

@ -553,6 +553,17 @@ class TestMessageAPI(TestEmailBase):
msg.set_charset(u'us-ascii')
self.assertEqual('us-ascii', msg.get_content_charset())
# Issue 5871: reject an attempt to embed a header inside a header value
# (header injection attack).
def test_embeded_header_via_Header_rejected(self):
msg = Message()
msg['Dummy'] = Header('dummy\nX-Injected-Header: test')
self.assertRaises(Errors.HeaderParseError, msg.as_string)
def test_embeded_header_via_string_rejected(self):
msg = Message()
msg['Dummy'] = 'dummy\nX-Injected-Header: test'
self.assertRaises(Errors.HeaderParseError, msg.as_string)
# Test the email.Encoders module

View file

@ -29,6 +29,13 @@ Core and Builtins
Library
-------
- Issue #10827: Changed the rules for 2-digit years. The time.asctime
function will now format any year when ``time.accept2dyear`` is
false and will accept years >= 1000 otherwise. The year range
accepted by ``time.mktime`` and ``time.strftime`` is still system
dependent, but ``time.mktime`` will now accept full range supported
by the OS. Conversion of 2-digit years to 4-digit is deprecated.
- Issue #10827: Changed the rules for 2-digit years. The time.asctime
function will now format any year when ``time.accept2dyear`` is
false and will accept years >= 1000 otherwise. The year range