1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
Origin: upstream
Last-Update: 2014-05-14
Subject: Caches may be allowed to store and serve private data (CVE-2014-1418)
In certain situations, Django may allow caches to store private data
related to a particular session and then serve that data to requests
with a different session, or no session at all. This can both lead to
information disclosure, and can be a vector for cache poisoning.
When using Django sessions, Django will set a ``Vary: Cookie`` header
to ensure caches do not serve cached data to requests from other
sessions. However, older versions of Internet Explorer (most likely
only Internet Explorer 6, and Internet Explorer 7 if run on Windows XP
or Windows Server 2003) are unable to handle the ``Vary`` header in
combination with many content types. Therefore, Django would remove
the header if the request was made by Internet Explorer.
To remedy this, the special behavior for these older Internet
Explorer versions has been removed, and the ``Vary`` header is no
longer stripped from the response. In addition, modifications to the
``Cache-Control`` header for all Internet Explorer requests with a
``Content-Disposition`` header, have also been removed as they were
found to have similar issues.
--- a/django/core/handlers/base.py
+++ b/django/core/handlers/base.py
@@ -14,8 +14,6 @@
response_fixes = [
http.fix_location_header,
http.conditional_content_removal,
- http.fix_IE_for_attach,
- http.fix_IE_for_vary,
]
def __init__(self):
--- a/django/http/utils.py
+++ b/django/http/utils.py
@@ -31,57 +31,3 @@
if request.method == 'HEAD':
response.content = ''
return response
-
-def fix_IE_for_attach(request, response):
- """
- This function will prevent Django from serving a Content-Disposition header
- while expecting the browser to cache it (only when the browser is IE). This
- leads to IE not allowing the client to download.
- """
- useragent = request.META.get('HTTP_USER_AGENT', '').upper()
- if 'MSIE' not in useragent and 'CHROMEFRAME' not in useragent:
- return response
-
- offending_headers = ('no-cache', 'no-store')
- if response.has_header('Content-Disposition'):
- try:
- del response['Pragma']
- except KeyError:
- pass
- if response.has_header('Cache-Control'):
- cache_control_values = [value.strip() for value in
- response['Cache-Control'].split(',')
- if value.strip().lower() not in offending_headers]
-
- if not len(cache_control_values):
- del response['Cache-Control']
- else:
- response['Cache-Control'] = ', '.join(cache_control_values)
-
- return response
-
-def fix_IE_for_vary(request, response):
- """
- This function will fix the bug reported at
- http://support.microsoft.com/kb/824847/en-us?spid=8722&sid=global
- by clearing the Vary header whenever the mime-type is not safe
- enough for Internet Explorer to handle. Poor thing.
- """
- useragent = request.META.get('HTTP_USER_AGENT', '').upper()
- if 'MSIE' not in useragent and 'CHROMEFRAME' not in useragent:
- return response
-
- # These mime-types that are decreed "Vary-safe" for IE:
- safe_mime_types = ('text/html', 'text/plain', 'text/sgml')
-
- # The first part of the Content-Type field will be the MIME type,
- # everything after ';', such as character-set, can be ignored.
- mime_type = response.get('Content-Type', '').partition(';')[0]
- if mime_type not in safe_mime_types:
- try:
- del response['Vary']
- except KeyError:
- pass
-
- return response
-
--- a/tests/regressiontests/utils/http.py
+++ b/tests/regressiontests/utils/http.py
@@ -56,50 +56,6 @@
]
self.assertTrue(result in acceptable_results)
- def test_fix_IE_for_vary(self):
- """
- Regression for #16632.
-
- `fix_IE_for_vary` shouldn't crash when there's no Content-Type header.
- """
-
- # functions to generate responses
- def response_with_unsafe_content_type():
- r = HttpResponse(content_type="text/unsafe")
- r['Vary'] = 'Cookie'
- return r
-
- def no_content_response_with_unsafe_content_type():
- # 'Content-Type' always defaulted, so delete it
- r = response_with_unsafe_content_type()
- del r['Content-Type']
- return r
-
- # request with & without IE user agent
- rf = RequestFactory()
- request = rf.get('/')
- ie_request = rf.get('/', HTTP_USER_AGENT='MSIE')
-
- # not IE, unsafe_content_type
- response = response_with_unsafe_content_type()
- utils.fix_IE_for_vary(request, response)
- self.assertTrue('Vary' in response)
-
- # IE, unsafe_content_type
- response = response_with_unsafe_content_type()
- utils.fix_IE_for_vary(ie_request, response)
- self.assertFalse('Vary' in response)
-
- # not IE, no_content
- response = no_content_response_with_unsafe_content_type()
- utils.fix_IE_for_vary(request, response)
- self.assertTrue('Vary' in response)
-
- # IE, no_content
- response = no_content_response_with_unsafe_content_type()
- utils.fix_IE_for_vary(ie_request, response)
- self.assertFalse('Vary' in response)
-
def test_base36(self):
# reciprocity works
for n in [0, 1, 1000, 1000000, sys.maxint]:
|