[1.11.x] Fixed #30070, CVE-2019-3498 -- Fixed content spoofing possiblity in the default 404 page.
Co-Authored-By: Tim Graham <timograham@gmail.com> Backport of 1ecc0a395be721e987e8e9fdfadde952b6dee1c7 from master.
This commit is contained in:
parent
b683bb0c9f
commit
1cd00fcf52
@ -2,6 +2,7 @@ from django import http
|
||||
from django.template import Context, Engine, TemplateDoesNotExist, loader
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.http import urlquote
|
||||
from django.views.decorators.csrf import requires_csrf_token
|
||||
|
||||
ERROR_404_TEMPLATE_NAME = '404.html'
|
||||
@ -21,7 +22,8 @@ def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME):
|
||||
Templates: :template:`404.html`
|
||||
Context:
|
||||
request_path
|
||||
The path of the requested URL (e.g., '/app/pages/bad_page/')
|
||||
The path of the requested URL (e.g., '/app/pages/bad_page/'). It's
|
||||
quoted to prevent a content injection attack.
|
||||
exception
|
||||
The message from the exception which triggered the 404 (if one was
|
||||
supplied), or the exception class name
|
||||
@ -37,7 +39,7 @@ def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME):
|
||||
if isinstance(message, six.text_type):
|
||||
exception_repr = message
|
||||
context = {
|
||||
'request_path': request.path,
|
||||
'request_path': urlquote(request.path),
|
||||
'exception': exception_repr,
|
||||
}
|
||||
try:
|
||||
@ -50,7 +52,7 @@ def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME):
|
||||
raise
|
||||
template = Engine().from_string(
|
||||
'<h1>Not Found</h1>'
|
||||
'<p>The requested URL {{ request_path }} was not found on this server.</p>')
|
||||
'<p>The requested resource was not found on this server.</p>')
|
||||
body = template.render(Context(context))
|
||||
content_type = 'text/html'
|
||||
return http.HttpResponseNotFound(body, content_type=content_type)
|
||||
|
18
docs/releases/1.11.18.txt
Normal file
18
docs/releases/1.11.18.txt
Normal file
@ -0,0 +1,18 @@
|
||||
============================
|
||||
Django 1.11.18 release notes
|
||||
============================
|
||||
|
||||
*January 4, 2019*
|
||||
|
||||
Django 1.11.18 fixes a security issue in 1.11.17.
|
||||
|
||||
CVE-2019-3498: Content spoofing possibility in the default 404 page
|
||||
-------------------------------------------------------------------
|
||||
|
||||
An attacker could craft a malicious URL that could make spoofed content appear
|
||||
on the default page generated by the ``django.views.defaults.page_not_found()``
|
||||
view.
|
||||
|
||||
The URL path is no longer displayed in the default 404 template and the
|
||||
``request_path`` context variable is now quoted to fix the issue for custom
|
||||
templates that use the path.
|
@ -26,6 +26,7 @@ versions of the documentation contain the release notes for any later releases.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
1.11.18
|
||||
1.11.17
|
||||
1.11.16
|
||||
1.11.15
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
@ -19,6 +20,8 @@ try:
|
||||
except ImportError: # Python < 3.5
|
||||
HTTPStatus = None
|
||||
|
||||
PY37 = sys.version_info >= (3, 7, 0)
|
||||
|
||||
|
||||
class HandlerTests(SimpleTestCase):
|
||||
|
||||
@ -184,16 +187,17 @@ class HandlerRequestTests(SimpleTestCase):
|
||||
|
||||
def test_invalid_urls(self):
|
||||
response = self.client.get('~%A9helloworld')
|
||||
self.assertContains(response, '~%A9helloworld', status_code=404)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
self.assertEqual(response.context['request_path'], '/~%25A9helloworld' if PY37 else '/%7E%25A9helloworld')
|
||||
|
||||
response = self.client.get('d%aao%aaw%aan%aal%aao%aaa%aad%aa/')
|
||||
self.assertContains(response, 'd%AAo%AAw%AAn%AAl%AAo%AAa%AAd%AA', status_code=404)
|
||||
self.assertEqual(response.context['request_path'], '/d%25AAo%25AAw%25AAn%25AAl%25AAo%25AAa%25AAd%25AA')
|
||||
|
||||
response = self.client.get('/%E2%99%E2%99%A5/')
|
||||
self.assertContains(response, '%E2%99\u2665', status_code=404)
|
||||
self.assertEqual(response.context['request_path'], '/%25E2%2599%E2%99%A5/')
|
||||
|
||||
response = self.client.get('/%E2%98%8E%E2%A9%E2%99%A5/')
|
||||
self.assertContains(response, '\u260e%E2%A9\u2665', status_code=404)
|
||||
self.assertEqual(response.context['request_path'], '/%E2%98%8E%25E2%25A9%E2%99%A5/')
|
||||
|
||||
def test_environ_path_info_type(self):
|
||||
environ = RequestFactory().get('/%E2%A8%87%87%A5%E2%A8%A0').environ
|
||||
|
Loading…
x
Reference in New Issue
Block a user