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:
parent
50778ab4c2
commit
389af00371
|
@ -46,6 +46,10 @@ ecre = re.compile(r'''
|
||||||
# For use with .match()
|
# For use with .match()
|
||||||
fcre = re.compile(r'[\041-\176]+:$')
|
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
|
# Helpers
|
||||||
|
@ -305,7 +309,11 @@ class Header:
|
||||||
if len(lines) > 1:
|
if len(lines) > 1:
|
||||||
formatter.newline()
|
formatter.newline()
|
||||||
formatter.add_transition()
|
formatter.add_transition()
|
||||||
return str(formatter)
|
value = str(formatter)
|
||||||
|
if _embeded_header.search(value):
|
||||||
|
raise HeaderParseError("header value appears to contain "
|
||||||
|
"an embedded header: {!r}".format(value))
|
||||||
|
return value
|
||||||
|
|
||||||
def _normalize(self):
|
def _normalize(self):
|
||||||
# Step 1: Normalize the chunks so that all runs of identical charsets
|
# Step 1: Normalize the chunks so that all runs of identical charsets
|
||||||
|
|
|
@ -540,6 +540,19 @@ class TestMessageAPI(TestEmailBase):
|
||||||
msg['Content-Disposition'])
|
msg['Content-Disposition'])
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
# Test the email.encoders module
|
||||||
class TestEncoders(unittest.TestCase):
|
class TestEncoders(unittest.TestCase):
|
||||||
def test_encode_empty_payload(self):
|
def test_encode_empty_payload(self):
|
||||||
|
|
|
@ -31,6 +31,13 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #5871: email.header.Header.encode now raises an error if any
|
||||||
|
continuation line in the formatted value has no leading white space
|
||||||
|
and looks like a header. Since Generator uses Header to format all
|
||||||
|
headers, this check is made for all headers in any serialized message
|
||||||
|
at serialization time. This provides protection against header
|
||||||
|
injection attacks.
|
||||||
|
|
||||||
- Issue #7858: Raise an error properly when os.utime() fails under Windows
|
- Issue #7858: Raise an error properly when os.utime() fails under Windows
|
||||||
on an existing file.
|
on an existing file.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue