티스토리 수익 글 보기

티스토리 수익 글 보기

[1.7.x] Prevented leaking the CSRF token through caching. · django/django@380545b · GitHub
Skip to content

Commit 380545b

Browse files
aaugustintimgraham
authored andcommitted
[1.7.x] Prevented leaking the CSRF token through caching.
This is a security fix. Disclosure will follow shortly. Backport of c083e38 from master
1 parent 5467405 commit 380545b

File tree

2 files changed

+36
1
lines changed

2 files changed

+36
1
lines changed

django/middleware/cache.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747

4848
from django.conf import settings
4949
from django.core.cache import caches, DEFAULT_CACHE_ALIAS
50-
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
50+
from django.utils.cache import (get_cache_key, get_max_age, has_vary_header,
51+
learn_cache_key, patch_response_headers)
5152
from django.utils.deprecation import RemovedInDjango18Warning
5253

5354

@@ -91,8 +92,15 @@ def process_response(self, request, response):
9192
if not self._should_update_cache(request, response):
9293
# We don't need to update the cache, just return.
9394
return response
95+
9496
if response.streaming or response.status_code != 200:
9597
return response
98+
99+
# Don't cache responses that set a user-specific (and maybe security
100+
# sensitive) cookie in response to a cookie-less request.
101+
if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'):
102+
return response
103+
96104
# Try to get the timeout from the "max-age" section of the "Cache-
97105
# Control" header before reverting to using the default cache_timeout
98106
# length.

tests/cache/tests.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
from django.core import management
1919
from django.core.cache import (cache, caches, CacheKeyWarning,
2020
InvalidCacheBackendError, DEFAULT_CACHE_ALIAS)
21+
from django.core.context_processors import csrf
2122
from django.db import connection, router, transaction
2223
from django.core.cache.utils import make_template_fragment_key
2324
from django.http import HttpResponse, StreamingHttpResponse
2425
from django.middleware.cache import (FetchFromCacheMiddleware,
2526
UpdateCacheMiddleware, CacheMiddleware)
27+
from django.middleware.csrf import CsrfViewMiddleware
2628
from django.template import Template
2729
from django.template.response import TemplateResponse
2830
from django.test import TestCase, TransactionTestCase, RequestFactory, override_settings
@@ -1739,6 +1741,10 @@ def hello_world_view(request, value):
17391741
return HttpResponse('Hello World %s' % value)
17401742

17411743

1744+
def csrf_view(request):
1745+
return HttpResponse(csrf(request)['csrf_token'])
1746+
1747+
17421748
@override_settings(
17431749
CACHE_MIDDLEWARE_ALIAS='other',
17441750
CACHE_MIDDLEWARE_KEY_PREFIX='middlewareprefix',
@@ -1958,6 +1964,27 @@ def test_view_decorator(self):
19581964
response = other_with_prefix_view(request, '16')
19591965
self.assertEqual(response.content, b'Hello World 16')
19601966

1967+
def test_sensitive_cookie_not_cached(self):
1968+
"""
1969+
Django must prevent caching of responses that set a user-specific (and
1970+
maybe security sensitive) cookie in response to a cookie-less request.
1971+
"""
1972+
csrf_middleware = CsrfViewMiddleware()
1973+
cache_middleware = CacheMiddleware()
1974+
1975+
request = self.factory.get('/view/')
1976+
self.assertIsNone(cache_middleware.process_request(request))
1977+
1978+
csrf_middleware.process_view(request, csrf_view, (), {})
1979+
1980+
response = csrf_view(request)
1981+
1982+
response = csrf_middleware.process_response(request, response)
1983+
response = cache_middleware.process_response(request, response)
1984+
1985+
# Inserting a CSRF cookie in a cookie-less request prevented caching.
1986+
self.assertIsNone(cache_middleware.process_request(request))
1987+
19611988

19621989
@override_settings(
19631990
CACHE_MIDDLEWARE_KEY_PREFIX='settingsprefix',

0 commit comments

Comments
 (0)