[Python-modules-commits] [python-django] 08/10: Fixed CVE-2016-7401 -- Fixed CSRF protection bypass on a site
Luke Faraone
lfaraone at moszumanska.debian.org
Sat Oct 29 20:54:11 UTC 2016
This is an automated email from the git hooks/post-receive script.
lfaraone pushed a commit to branch debian/jessie
in repository python-django.
commit b66a3bcd305248e7e246884fd7906a75d69ffc94
Author: Collin Anderson <cmawebsite at gmail.com>
Date: Fri Mar 11 21:36:08 2016 -0500
Fixed CVE-2016-7401 -- Fixed CSRF protection bypass on a site
with Google Analytics.
This is a security fix.
Backport of "refs #26158 -- rewrote http.parse_cookie() to better match
browsers." 93a135d111c2569d88d65a3f4ad9e6d9ad291452 from master
---
django/http/cookie.py | 29 ++++++++++++++------------
tests/httpwrappers/tests.py | 50 ++++++++++++++++++++++++++++++++++++++++++++-
tests/requests/tests.py | 5 +----
3 files changed, 66 insertions(+), 18 deletions(-)
diff --git a/django/http/cookie.py b/django/http/cookie.py
index 7084c87..07d8cbf 100644
--- a/django/http/cookie.py
+++ b/django/http/cookie.py
@@ -71,18 +71,21 @@ else:
def parse_cookie(cookie):
- if cookie == '':
- return {}
- if not isinstance(cookie, http_cookies.BaseCookie):
- try:
- c = SimpleCookie()
- c.load(cookie)
- except http_cookies.CookieError:
- # Invalid cookie
- return {}
- else:
- c = cookie
+ """
+ Return a dictionary parsed from a `Cookie:` header string.
+ """
cookiedict = {}
- for key in c.keys():
- cookiedict[key] = c.get(key).value
+ if six.PY2:
+ cookie = force_str(cookie)
+ for chunk in cookie.split(str(';')):
+ if str('=') in chunk:
+ key, val = chunk.split(str('='), 1)
+ else:
+ # Assume an empty name per
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=169091
+ key, val = str(''), chunk
+ key, val = key.strip(), val.strip()
+ if key or val:
+ # unquote using Python's algorithm.
+ cookiedict[key] = http_cookies._unquote(val)
return cookiedict
diff --git a/tests/httpwrappers/tests.py b/tests/httpwrappers/tests.py
index 7881f2f..25a9127 100644
--- a/tests/httpwrappers/tests.py
+++ b/tests/httpwrappers/tests.py
@@ -19,7 +19,7 @@ from django.http import (QueryDict, HttpResponse, HttpResponseRedirect,
parse_cookie)
from django.test import TestCase
from django.utils.deprecation import RemovedInDjango18Warning
-from django.utils.encoding import smart_str, force_text
+from django.utils.encoding import smart_str, force_text, force_str
from django.utils.functional import lazy
from django.utils._os import upath
from django.utils import six
@@ -632,6 +632,8 @@ class CookieTests(unittest.TestCase):
c2 = SimpleCookie()
c2.load(c.output())
self.assertEqual(c['test'].value, c2['test'].value)
+ c3 = parse_cookie(c.output()[12:])
+ self.assertEqual(c['test'].value, c3['test'])
def test_nonstandard_keys(self):
"""
@@ -645,6 +647,52 @@ class CookieTests(unittest.TestCase):
"""
self.assertTrue('good_cookie' in parse_cookie('a:=b; a:=c; good_cookie=yes').keys())
+ def test_python_cookies(self):
+ """
+ Test cases copied from Python's Lib/test/test_http_cookies.py
+ """
+ self.assertEqual(parse_cookie('chips=ahoy; vienna=finger'), {'chips': 'ahoy', 'vienna': 'finger'})
+ # Here parse_cookie() differs from Python's cookie parsing in that it
+ # treats all semicolons as delimiters, even within quotes.
+ self.assertEqual(
+ parse_cookie('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'),
+ {'keebler': '"E=mc2', 'L': '\\"Loves\\"', 'fudge': '\\012', '': '"'}
+ )
+ # Illegal cookies that have an '=' char in an unquoted value.
+ self.assertEqual(parse_cookie('keebler=E=mc2'), {'keebler': 'E=mc2'})
+ # Cookies with ':' character in their name.
+ self.assertEqual(parse_cookie('key:term=value:term'), {'key:term': 'value:term'})
+ # Cookies with '[' and ']'.
+ self.assertEqual(parse_cookie('a=b; c=[; d=r; f=h'), {'a': 'b', 'c': '[', 'd': 'r', 'f': 'h'})
+
+ def test_cookie_edgecases(self):
+ # Cookies that RFC6265 allows.
+ self.assertEqual(parse_cookie('a=b; Domain=example.com'), {'a': 'b', 'Domain': 'example.com'})
+ # parse_cookie() has historically kept only the last cookie with the
+ # same name.
+ self.assertEqual(parse_cookie('a=b; h=i; a=c'), {'a': 'c', 'h': 'i'})
+
+ def test_invalid_cookies(self):
+ """
+ Cookie strings that go against RFC6265 but browsers will send if set
+ via document.cookie.
+ """
+ # Chunks without an equals sign appear as unnamed values per
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=169091
+ self.assertIn('django_language', parse_cookie('abc=def; unnamed; django_language=en').keys())
+ # Even a double quote may be an unamed value.
+ self.assertEqual(parse_cookie('a=b; "; c=d'), {'a': 'b', '': '"', 'c': 'd'})
+ # Spaces in names and values, and an equals sign in values.
+ self.assertEqual(parse_cookie('a b c=d e = f; gh=i'), {'a b c': 'd e = f', 'gh': 'i'})
+ # More characters the spec forbids.
+ self.assertEqual(parse_cookie('a b,c<>@:/[]?{}=d " =e,f g'), {'a b,c<>@:/[]?{}': 'd " =e,f g'})
+ # Unicode characters. The spec only allows ASCII.
+ self.assertEqual(parse_cookie('saint=André Bessette'), {'saint': force_str('André Bessette')})
+ # Browsers don't send extra whitespace or semicolons in Cookie headers,
+ # but parse_cookie() should parse whitespace the same way
+ # document.cookie parses whitespace.
+ self.assertEqual(parse_cookie(' = b ; ; = ; c = ; '), {'': 'b', 'c': ''})
+
def test_httponly_after_load(self):
"""
Test that we can use httponly attribute on cookies that we load
diff --git a/tests/requests/tests.py b/tests/requests/tests.py
index 55b37bb..6364ab1 100644
--- a/tests/requests/tests.py
+++ b/tests/requests/tests.py
@@ -11,7 +11,7 @@ from django.db import connection, connections
from django.core import signals
from django.core.exceptions import SuspiciousOperation
from django.core.handlers.wsgi import WSGIRequest, LimitedStream
-from django.http import (HttpRequest, HttpResponse, parse_cookie,
+from django.http import (HttpRequest, HttpResponse,
build_request_repr, UnreadablePostError, RawPostDataException)
from django.test import SimpleTestCase, TransactionTestCase, override_settings
from django.test.client import FakePayload
@@ -128,9 +128,6 @@ class RequestsTests(SimpleTestCase):
request = WSGIRequest({'PATH_INFO': wsgi_str("/سلام/"), 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
self.assertEqual(request.path, "/سلام/")
- def test_parse_cookie(self):
- self.assertEqual(parse_cookie('invalid at key=true'), {})
-
def test_httprequest_location(self):
request = HttpRequest()
self.assertEqual(request.build_absolute_uri(location="https://www.example.com/asdf"),
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django.git
More information about the Python-modules-commits
mailing list