1
0
mirror of https://github.com/django/django.git synced 2025-06-09 05:29:13 +00:00

[1.4.x] Prevented arbitrary file inclusion with {% ssi %} tag and relative paths.

Thanks Rainer Koirikivi for the report and draft patch.

This is a security fix; disclosure to follow shortly.

Backport of 7fe5b656c9 from master
This commit is contained in:
Tim Graham 2013-08-27 21:06:33 -04:00
parent 9ab7ed9b72
commit 87d2750b39
2 changed files with 33 additions and 0 deletions

View File

@ -1,5 +1,6 @@
"""Default tags used by the template system, available to all templates.""" """Default tags used by the template system, available to all templates."""
import os
import sys import sys
import re import re
from datetime import datetime from datetime import datetime
@ -309,6 +310,7 @@ class RegroupNode(Node):
return '' return ''
def include_is_allowed(filepath): def include_is_allowed(filepath):
filepath = os.path.abspath(filepath)
for root in settings.ALLOWED_INCLUDE_ROOTS: for root in settings.ALLOWED_INCLUDE_ROOTS:
if filepath.startswith(root): if filepath.startswith(root):
return True return True

View File

@ -1764,3 +1764,34 @@ class RequestContextTests(BaseTemplateResponseTest):
template.Template('{% include "child" only %}').render(ctx), template.Template('{% include "child" only %}').render(ctx),
'none' 'none'
) )
class SSITests(unittest.TestCase):
def setUp(self):
self.this_dir = os.path.dirname(os.path.abspath(__file__))
self.ssi_dir = os.path.join(self.this_dir, "templates", "first")
def render_ssi(self, path):
# the path must exist for the test to be reliable
self.assertTrue(os.path.exists(path))
return template.Template('{%% ssi %s %%}' % path).render(Context())
def test_allowed_paths(self):
acceptable_path = os.path.join(self.ssi_dir, "..", "first", "test.html")
with override_settings(ALLOWED_INCLUDE_ROOTS=(self.ssi_dir,)):
self.assertEqual(self.render_ssi(acceptable_path), 'First template\n')
def test_relative_include_exploit(self):
"""
May not bypass ALLOWED_INCLUDE_ROOTS with relative paths
e.g. if ALLOWED_INCLUDE_ROOTS = ("/var/www",), it should not be
possible to do {% ssi "/var/www/../../etc/passwd" %}
"""
disallowed_paths = [
os.path.join(self.ssi_dir, "..", "ssi_include.html"),
os.path.join(self.ssi_dir, "..", "second", "test.html"),
]
with override_settings(ALLOWED_INCLUDE_ROOTS=(self.ssi_dir,)):
for path in disallowed_paths:
self.assertEqual(self.render_ssi(path), '')