diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2015-03-12 09:15:15 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2015-03-12 09:15:15 (GMT) |
commit | b669bfc2bed1f5487ac2762bff53b55f6155bb60 (patch) | |
tree | 5e4611fc1496efe54fd582b5680c8c3dbe562d26 /Lib/http | |
parent | 411bf641d3b820aa5e55718d5c5770543fa32255 (diff) | |
parent | a112a8ae47813f75aa8ad27ee8c42a7c2e937d13 (diff) | |
download | cpython-b669bfc2bed1f5487ac2762bff53b55f6155bb60.zip cpython-b669bfc2bed1f5487ac2762bff53b55f6155bb60.tar.gz cpython-b669bfc2bed1f5487ac2762bff53b55f6155bb60.tar.bz2 |
Issue #22928: Disabled HTTP header injections in http.client.
Original patch by Demian Brecht.
Diffstat (limited to 'Lib/http')
-rw-r--r-- | Lib/http/client.py | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/Lib/http/client.py b/Lib/http/client.py index 5e12a85..d2709ae 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -71,6 +71,7 @@ import email.message import http import io import os +import re import socket import collections from urllib.parse import urlsplit @@ -109,6 +110,34 @@ MAXAMOUNT = 1048576 _MAXLINE = 65536 _MAXHEADERS = 100 +# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) +# +# VCHAR = %x21-7E +# obs-text = %x80-FF +# header-field = field-name ":" OWS field-value OWS +# field-name = token +# field-value = *( field-content / obs-fold ) +# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +# field-vchar = VCHAR / obs-text +# +# obs-fold = CRLF 1*( SP / HTAB ) +# ; obsolete line folding +# ; see Section 3.2.4 + +# token = 1*tchar +# +# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" +# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" +# / DIGIT / ALPHA +# ; any VCHAR, except delimiters +# +# VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1 + +# the patterns for both name and value are more leniant than RFC +# definitions to allow for backwards compatibility +_is_legal_header_name = re.compile(rb'[^:\s][^:\r\n]*').fullmatch +_is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search + class HTTPMessage(email.message.Message): # XXX The only usage of this method is in @@ -1002,12 +1031,20 @@ class HTTPConnection: if hasattr(header, 'encode'): header = header.encode('ascii') + + if not _is_legal_header_name(header): + raise ValueError('Invalid header name %r' % (header,)) + values = list(values) for i, one_value in enumerate(values): if hasattr(one_value, 'encode'): values[i] = one_value.encode('latin-1') elif isinstance(one_value, int): values[i] = str(one_value).encode('ascii') + + if _is_illegal_header_value(values[i]): + raise ValueError('Invalid header value %r' % (values[i],)) + value = b'\r\n\t'.join(values) header = header + b': ' + value self._output(header) |