Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd1bc980

Browse files
collinandersontimgraham
authored andcommitted
[1.9.x] FixedCVE-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 matchbrowsers."93a135d from master
1 parent07760d0 commitd1bc980

File tree

6 files changed

+105
-18
lines changed

6 files changed

+105
-18
lines changed

‎django/http/cookie.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,21 @@ def _BaseCookie__set(self, key, real_value, coded_value):
8989

9090

9191
defparse_cookie(cookie):
92-
ifcookie=='':
93-
return {}
94-
ifnotisinstance(cookie,http_cookies.BaseCookie):
95-
try:
96-
c=SimpleCookie()
97-
c.load(cookie)
98-
excepthttp_cookies.CookieError:
99-
# Invalid cookie
100-
return {}
101-
else:
102-
c=cookie
92+
"""
93+
Return a dictionary parsed from a `Cookie:` header string.
94+
"""
10395
cookiedict= {}
104-
forkeyinc.keys():
105-
cookiedict[key]=c.get(key).value
96+
ifsix.PY2:
97+
cookie=force_str(cookie)
98+
forchunkincookie.split(str(';')):
99+
ifstr('=')inchunk:
100+
key,val=chunk.split(str('='),1)
101+
else:
102+
# Assume an empty name per
103+
# https://bugzilla.mozilla.org/show_bug.cgi?id=169091
104+
key,val=str(''),chunk
105+
key,val=key.strip(),val.strip()
106+
ifkeyorval:
107+
# unquote using Python's algorithm.
108+
cookiedict[key]=http_cookies._unquote(val)
106109
returncookiedict

‎docs/releases/1.8.15.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
===========================
2+
Django 1.8.15 release notes
3+
===========================
4+
5+
*September 26, 2016*
6+
7+
Django 1.8.15 fixes a security issue in 1.8.14.
8+
9+
CSRF protection bypass on a site with Google Analytics
10+
======================================================
11+
12+
An interaction between Google Analytics and Django's cookie parsing could allow
13+
an attacker to set arbitrary cookies leading to a bypass of CSRF protection.
14+
15+
The parser for ``request.COOKIES`` is simplified to better match the behavior
16+
of browsers and to mitigate this attack. ``request.COOKIES`` may now contain
17+
cookies that are invalid according to :rfc:`6265` but are possible to set via
18+
``document.cookie``.

‎docs/releases/1.9.10.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
===========================
2+
Django 1.9.10 release notes
3+
===========================
4+
5+
*September 26, 2016*
6+
7+
Django 1.9.10 fixes a security issue in 1.9.9.
8+
9+
CSRF protection bypass on a site with Google Analytics
10+
======================================================
11+
12+
An interaction between Google Analytics and Django's cookie parsing could allow
13+
an attacker to set arbitrary cookies leading to a bypass of CSRF protection.
14+
15+
The parser for ``request.COOKIES`` is simplified to better match the behavior
16+
of browsers and to mitigate this attack. ``request.COOKIES`` may now contain
17+
cookies that are invalid according to :rfc:`6265` but are possible to set via
18+
``document.cookie``.

‎docs/releases/index.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ versions of the documentation contain the release notes for any later releases.
2525
.. toctree::
2626
:maxdepth: 1
2727

28+
1.9.10
2829
1.9.9
2930
1.9.8
3031
1.9.7
@@ -41,6 +42,7 @@ versions of the documentation contain the release notes for any later releases.
4142
.. toctree::
4243
:maxdepth: 1
4344

45+
1.8.15
4446
1.8.14
4547
1.8.13
4648
1.8.12

‎tests/httpwrappers/tests.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
fromdjango.testimportSimpleTestCase
2222
fromdjango.utilsimportsix
2323
fromdjango.utils._osimportupath
24-
fromdjango.utils.encodingimportforce_text,smart_str
24+
fromdjango.utils.encodingimportforce_str,force_text,smart_str
2525
fromdjango.utils.functionalimportlazy
2626

2727
lazystr=lazy(force_text,six.text_type)
@@ -657,6 +657,8 @@ def test_decode(self):
657657
c2=SimpleCookie()
658658
c2.load(c.output()[12:])
659659
self.assertEqual(c['test'].value,c2['test'].value)
660+
c3=parse_cookie(c.output()[12:])
661+
self.assertEqual(c['test'].value,c3['test'])
660662

661663
deftest_decode_2(self):
662664
"""
@@ -667,6 +669,8 @@ def test_decode_2(self):
667669
c2=SimpleCookie()
668670
c2.load(c.output()[12:])
669671
self.assertEqual(c['test'].value,c2['test'].value)
672+
c3=parse_cookie(c.output()[12:])
673+
self.assertEqual(c['test'].value,c3['test'])
670674

671675
deftest_nonstandard_keys(self):
672676
"""
@@ -680,6 +684,52 @@ def test_repeated_nonstandard_keys(self):
680684
"""
681685
self.assertIn('good_cookie',parse_cookie('a:=b; a:=c; good_cookie=yes').keys())
682686

687+
deftest_python_cookies(self):
688+
"""
689+
Test cases copied from Python's Lib/test/test_http_cookies.py
690+
"""
691+
self.assertEqual(parse_cookie('chips=ahoy; vienna=finger'), {'chips':'ahoy','vienna':'finger'})
692+
# Here parse_cookie() differs from Python's cookie parsing in that it
693+
# treats all semicolons as delimiters, even within quotes.
694+
self.assertEqual(
695+
parse_cookie('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'),
696+
{'keebler':'"E=mc2','L':'\\"Loves\\"','fudge':'\\012','':'"'}
697+
)
698+
# Illegal cookies that have an '=' char in an unquoted value.
699+
self.assertEqual(parse_cookie('keebler=E=mc2'), {'keebler':'E=mc2'})
700+
# Cookies with ':' character in their name.
701+
self.assertEqual(parse_cookie('key:term=value:term'), {'key:term':'value:term'})
702+
# Cookies with '[' and ']'.
703+
self.assertEqual(parse_cookie('a=b; c=[; d=r; f=h'), {'a':'b','c':'[','d':'r','f':'h'})
704+
705+
deftest_cookie_edgecases(self):
706+
# Cookies that RFC6265 allows.
707+
self.assertEqual(parse_cookie('a=b; Domain=example.com'), {'a':'b','Domain':'example.com'})
708+
# parse_cookie() has historically kept only the last cookie with the
709+
# same name.
710+
self.assertEqual(parse_cookie('a=b; h=i; a=c'), {'a':'c','h':'i'})
711+
712+
deftest_invalid_cookies(self):
713+
"""
714+
Cookie strings that go against RFC6265 but browsers will send if set
715+
via document.cookie.
716+
"""
717+
# Chunks without an equals sign appear as unnamed values per
718+
# https://bugzilla.mozilla.org/show_bug.cgi?id=169091
719+
self.assertIn('django_language',parse_cookie('abc=def; unnamed; django_language=en').keys())
720+
# Even a double quote may be an unamed value.
721+
self.assertEqual(parse_cookie('a=b; "; c=d'), {'a':'b','':'"','c':'d'})
722+
# Spaces in names and values, and an equals sign in values.
723+
self.assertEqual(parse_cookie('a b c=d e = f; gh=i'), {'a b c':'d e = f','gh':'i'})
724+
# More characters the spec forbids.
725+
self.assertEqual(parse_cookie('a b,c<>@:/[]?{}=d " =e,f g'), {'a b,c<>@:/[]?{}':'d " =e,f g'})
726+
# Unicode characters. The spec only allows ASCII.
727+
self.assertEqual(parse_cookie('saint=André Bessette'), {'saint':force_str('André Bessette')})
728+
# Browsers don't send extra whitespace or semicolons in Cookie headers,
729+
# but parse_cookie() should parse whitespace the same way
730+
# document.cookie parses whitespace.
731+
self.assertEqual(parse_cookie(' = b ; ; = ; c = ; '), {'':'b','c':''})
732+
683733
deftest_httponly_after_load(self):
684734
"""
685735
Test that we can use httponly attribute on cookies that we load

‎tests/requests/tests.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
fromdjango.core.handlers.wsgiimportLimitedStream,WSGIRequest
1111
fromdjango.httpimport (
1212
HttpRequest,HttpResponse,RawPostDataException,UnreadablePostError,
13-
parse_cookie,
1413
)
1514
fromdjango.testimportRequestFactory,SimpleTestCase,override_settings
1615
fromdjango.test.clientimportFakePayload
@@ -154,9 +153,6 @@ def wsgi_str(path_info):
154153
request=WSGIRequest({'PATH_INFO':wsgi_str("/سلام/"),'REQUEST_METHOD':'get','wsgi.input':BytesIO(b'')})
155154
self.assertEqual(request.path,"/سلام/")
156155

157-
deftest_parse_cookie(self):
158-
self.assertEqual(parse_cookie('invalid@key=true'), {})
159-
160156
deftest_httprequest_location(self):
161157
request=HttpRequest()
162158
self.assertEqual(request.build_absolute_uri(location="https://www.example.com/asdf"),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp