mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.7.x] Prevented leaking the CSRF token through caching.
This is a security fix. Disclosure will follow shortly.
Backport of c083e3815a from master
			
			
This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						parent
						
							546740544d
						
					
				
				
					commit
					380545bf85
				
			| @@ -47,7 +47,8 @@ import warnings | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.core.cache import caches, DEFAULT_CACHE_ALIAS | ||||
| from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age | ||||
| from django.utils.cache import (get_cache_key, get_max_age, has_vary_header, | ||||
|     learn_cache_key, patch_response_headers) | ||||
| from django.utils.deprecation import RemovedInDjango18Warning | ||||
|  | ||||
|  | ||||
| @@ -91,8 +92,15 @@ class UpdateCacheMiddleware(object): | ||||
|         if not self._should_update_cache(request, response): | ||||
|             # We don't need to update the cache, just return. | ||||
|             return response | ||||
|  | ||||
|         if response.streaming or response.status_code != 200: | ||||
|             return response | ||||
|  | ||||
|         # Don't cache responses that set a user-specific (and maybe security | ||||
|         # sensitive) cookie in response to a cookie-less request. | ||||
|         if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'): | ||||
|             return response | ||||
|  | ||||
|         # Try to get the timeout from the "max-age" section of the "Cache- | ||||
|         # Control" header before reverting to using the default cache_timeout | ||||
|         # length. | ||||
|   | ||||
							
								
								
									
										27
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							| @@ -18,11 +18,13 @@ from django.conf import settings | ||||
| from django.core import management | ||||
| from django.core.cache import (cache, caches, CacheKeyWarning, | ||||
|     InvalidCacheBackendError, DEFAULT_CACHE_ALIAS) | ||||
| from django.core.context_processors import csrf | ||||
| from django.db import connection, router, transaction | ||||
| from django.core.cache.utils import make_template_fragment_key | ||||
| from django.http import HttpResponse, StreamingHttpResponse | ||||
| from django.middleware.cache import (FetchFromCacheMiddleware, | ||||
|     UpdateCacheMiddleware, CacheMiddleware) | ||||
| from django.middleware.csrf import CsrfViewMiddleware | ||||
| from django.template import Template | ||||
| from django.template.response import TemplateResponse | ||||
| from django.test import TestCase, TransactionTestCase, RequestFactory, override_settings | ||||
| @@ -1739,6 +1741,10 @@ def hello_world_view(request, value): | ||||
|     return HttpResponse('Hello World %s' % value) | ||||
|  | ||||
|  | ||||
| def csrf_view(request): | ||||
|     return HttpResponse(csrf(request)['csrf_token']) | ||||
|  | ||||
|  | ||||
| @override_settings( | ||||
|     CACHE_MIDDLEWARE_ALIAS='other', | ||||
|     CACHE_MIDDLEWARE_KEY_PREFIX='middlewareprefix', | ||||
| @@ -1958,6 +1964,27 @@ class CacheMiddlewareTest(IgnoreDeprecationWarningsMixin, TestCase): | ||||
|         response = other_with_prefix_view(request, '16') | ||||
|         self.assertEqual(response.content, b'Hello World 16') | ||||
|  | ||||
|     def test_sensitive_cookie_not_cached(self): | ||||
|         """ | ||||
|         Django must prevent caching of responses that set a user-specific (and | ||||
|         maybe security sensitive) cookie in response to a cookie-less request. | ||||
|         """ | ||||
|         csrf_middleware = CsrfViewMiddleware() | ||||
|         cache_middleware = CacheMiddleware() | ||||
|  | ||||
|         request = self.factory.get('/view/') | ||||
|         self.assertIsNone(cache_middleware.process_request(request)) | ||||
|  | ||||
|         csrf_middleware.process_view(request, csrf_view, (), {}) | ||||
|  | ||||
|         response = csrf_view(request) | ||||
|  | ||||
|         response = csrf_middleware.process_response(request, response) | ||||
|         response = cache_middleware.process_response(request, response) | ||||
|  | ||||
|         # Inserting a CSRF cookie in a cookie-less request prevented caching. | ||||
|         self.assertIsNone(cache_middleware.process_request(request)) | ||||
|  | ||||
|  | ||||
| @override_settings( | ||||
|     CACHE_MIDDLEWARE_KEY_PREFIX='settingsprefix', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user