diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2014-11-21 01:20:57 +0100 |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2014-11-21 01:20:57 +0100 |
commit | 8e72c979fdc31c06dff312c6f0ad641157595613 (patch) | |
tree | ac51023e671fa94229bde00a7967fb466d1b9987 /Lib/http/cookies.py | |
parent | 2da903a5fa0ba6becfb28b5c595e8d5381080540 (diff) | |
download | cpython-8e72c979fdc31c06dff312c6f0ad641157595613.tar.gz |
Issue #22796: HTTP cookie parsing is now stricter, in order to protect against potential injection attacks.
Diffstat (limited to 'Lib/http/cookies.py')
-rw-r--r-- | Lib/http/cookies.py | 56 |
1 files changed, 41 insertions, 15 deletions
diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index a6de6d5883..7ec927447c 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -533,10 +533,17 @@ class BaseCookie(dict): return def __parse_string(self, str, patt=_CookiePattern): - i = 0 # Our starting point - n = len(str) # Length of string - M = None # current morsel + i = 0 # Our starting point + n = len(str) # Length of string + parsed_items = [] # Parsed (type, key, value) triples + morsel_seen = False # A key=value pair was previously encountered + + TYPE_ATTRIBUTE = 1 + TYPE_KEYVALUE = 2 + # We first parse the whole cookie string and reject it if it's + # syntactically invalid (this helps avoid some classes of injection + # attacks). while 0 <= i < n: # Start looking for a cookie match = patt.match(str, i) @@ -547,22 +554,41 @@ class BaseCookie(dict): key, value = match.group("key"), match.group("val") i = match.end(0) - # Parse the key, value in case it's metainfo if key[0] == "$": - # We ignore attributes which pertain to the cookie - # mechanism as a whole. See RFC 2109. - # (Does anyone care?) - if M: - M[key[1:]] = value + if not morsel_seen: + # We ignore attributes which pertain to the cookie + # mechanism as a whole, such as "$Version". + # See RFC 2965. (Does anyone care?) + continue + parsed_items.append((TYPE_ATTRIBUTE, key[1:], value)) elif key.lower() in Morsel._reserved: - if M: - if value is None: - if key.lower() in Morsel._flags: - M[key] = True + if not morsel_seen: + # Invalid cookie string + return + if value is None: + if key.lower() in Morsel._flags: + parsed_items.append((TYPE_ATTRIBUTE, key, True)) else: - M[key] = _unquote(value) + # Invalid cookie string + return + else: + parsed_items.append((TYPE_ATTRIBUTE, key, _unquote(value))) elif value is not None: - rval, cval = self.value_decode(value) + parsed_items.append((TYPE_KEYVALUE, key, self.value_decode(value))) + morsel_seen = True + else: + # Invalid cookie string + return + + # The cookie string is valid, apply it. + M = None # current morsel + for tp, key, value in parsed_items: + if tp == TYPE_ATTRIBUTE: + assert M is not None + M[key] = value + else: + assert tp == TYPE_KEYVALUE + rval, cval = value self.__set(key, rval, cval) M = self[key] |