Fixed #17837. Improved markdown safety.

Markdown enable_attributes is now False when safe_mode is enabled. Documented
the markdown "safe" argument. Added warnings when the safe argument is
passed to versions of markdown which cannot be made safe. Deprecated
versions of markdown < 2.1. Many thanks to ptone for the patch.



git-svn-id: http://code.djangoproject.com/svn/django/trunk@17735 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Paul McMillan 2012-03-14 19:06:23 +00:00
parent eb9eaa6d71
commit 14df122f86
5 changed files with 70 additions and 3 deletions

View File

@ -11,6 +11,8 @@ markup syntaxes to HTML; currently there is support for:
* reStructuredText, which requires docutils from http://docutils.sf.net/ * reStructuredText, which requires docutils from http://docutils.sf.net/
""" """
import warnings
from django import template from django import template
from django.conf import settings from django.conf import settings
from django.utils.encoding import smart_str, force_unicode from django.utils.encoding import smart_str, force_unicode
@ -63,14 +65,25 @@ def markdown(value, arg=''):
safe_mode = True safe_mode = True
else: else:
safe_mode = False safe_mode = False
python_markdown_deprecation = "The use of Python-Markdown "
"< 2.1 in Django is deprecated; please update to the current version"
# Unicode support only in markdown v1.7 or above. Version_info # Unicode support only in markdown v1.7 or above. Version_info
# exist only in markdown v1.6.2rc-2 or above. # exist only in markdown v1.6.2rc-2 or above.
if getattr(markdown, "version_info", None) < (1,7): markdown_vers = getattr(markdown, "version_info", None)
if markdown_vers < (1,7):
warnings.warn(python_markdown_deprecation, DeprecationWarning)
return mark_safe(force_unicode(markdown.markdown(smart_str(value), extensions, safe_mode=safe_mode))) return mark_safe(force_unicode(markdown.markdown(smart_str(value), extensions, safe_mode=safe_mode)))
else: else:
return mark_safe(markdown.markdown(force_unicode(value), extensions, safe_mode=safe_mode)) if markdown_vers >= (2,1):
if safe_mode:
return mark_safe(markdown.markdown(force_unicode(value), extensions, safe_mode=safe_mode, enable_attributes=False))
else:
return mark_safe(markdown.markdown(force_unicode(value), extensions, safe_mode=safe_mode))
else:
warnings.warn(python_markdown_deprecation, DeprecationWarning)
return mark_safe(markdown.markdown(force_unicode(value), extensions, safe_mode=safe_mode))
else: else:
warnings.warn(python_markdown_deprecation, DeprecationWarning)
return mark_safe(force_unicode(markdown.markdown(smart_str(value)))) return mark_safe(force_unicode(markdown.markdown(smart_str(value))))
@register.filter(is_safe=True) @register.filter(is_safe=True)

View File

@ -58,6 +58,20 @@ Paragraph 2 with a link_
pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""") pattern = re.compile("""<p>Paragraph 1\s*</p>\s*<h2>\s*An h2</h2>""")
self.assertTrue(pattern.match(rendered)) self.assertTrue(pattern.match(rendered))
@unittest.skipUnless(markdown, 'markdown no installed')
def test_markdown_attribute_disable(self):
t = Template("{% load markup %}{{ markdown_content|markdown:'safe' }}")
markdown_content = "{@onclick=alert('hi')}some paragraph"
rendered = t.render(Context({'markdown_content':markdown_content})).strip()
self.assertTrue('@' in rendered)
@unittest.skipUnless(markdown, 'markdown no installed')
def test_markdown_attribute_enable(self):
t = Template("{% load markup %}{{ markdown_content|markdown }}")
markdown_content = "{@onclick=alert('hi')}some paragraph"
rendered = t.render(Context({'markdown_content':markdown_content})).strip()
self.assertFalse('@' in rendered)
@unittest.skipIf(markdown, 'markdown is installed') @unittest.skipIf(markdown, 'markdown is installed')
def test_no_markdown(self): def test_no_markdown(self):
t = Template("{% load markup %}{{ markdown_content|markdown }}") t = Template("{% load markup %}{{ markdown_content|markdown }}")

View File

@ -196,6 +196,11 @@ these changes.
filesystem path to a ``locale`` directory containing non-app-specific filesystem path to a ``locale`` directory containing non-app-specific
translations in its value. translations in its value.
* The Markup contrib app will no longer support versions of Python-Markdown
library earlier than 2.1. An accelerated timeline was used as this was
a security related deprecation.
1.6 1.6
--- ---

View File

@ -47,3 +47,19 @@ override the default writer settings. See the `restructuredtext writer
settings`_ for details on what these settings are. settings`_ for details on what these settings are.
.. _restructuredtext writer settings: http://docutils.sourceforge.net/docs/user/config.html#html4css1-writer .. _restructuredtext writer settings: http://docutils.sourceforge.net/docs/user/config.html#html4css1-writer
Markdown
--------
The Python Markdown library supports options named "safe_mode" and
"enable_attributes". Both relate to the security of the output. To enable both
options in tandem, the markdown filter supports the "safe" argument.
{{ markdown_content_var|markdown:"safe" }}
.. warning::
Versions of the Python-Markdown library prior to 2.1 do not support the
optional disabling of attributes and by default they will be included in
any output from the markdown filter - a warning is issued if this is the
case.

View File

@ -1096,6 +1096,16 @@ field. This was something that should not have worked, and in 1.4 loading such
incomplete fixtures will fail. Because fixtures are a raw import, they should incomplete fixtures will fail. Because fixtures are a raw import, they should
explicitly specify all field values, regardless of field options on the model. explicitly specify all field values, regardless of field options on the model.
Attributes disabled in markdown when safe mode set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prior to Django 1.4, attributes were included in any markdown output regardless
of safe mode setting of the filter. With version > 2.1 of the Python-Markdown
library, an enable_attributes option was added. When the safe argument is
passed to the markdown filter, both the ``safe_mode=True`` and
``enable_attributes=False`` options are set. If using a version of the
Python-Markdown library less than 2.1, a warning is issued that the output is
insecure.
Features deprecated in 1.4 Features deprecated in 1.4
========================== ==========================
@ -1262,3 +1272,12 @@ each request to a site map now creates a new Paginator object and calls the
``items()`` method is doing, this may have a negative performance impact. ``items()`` method is doing, this may have a negative performance impact.
To mitigate the performance impact, consider using the :doc:`caching To mitigate the performance impact, consider using the :doc:`caching
framework </topics/cache>` within your ``Sitemap`` subclass. framework </topics/cache>` within your ``Sitemap`` subclass.
Versions of Python-Markdown earlier than 2.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Versions of Python-Markdown earlier than 2.1 do not support the option to
disable attributes. As a security issue, earlier versions of this library will
not be supported by the markup contrib app in 1.5 under an accelerated
deprecation timeline.