]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
explain what autoescaping does 1072/head
authorDavid Lord <davidism@gmail.com>
Tue, 8 Oct 2019 20:42:48 +0000 (13:42 -0700)
committerDavid Lord <davidism@gmail.com>
Tue, 8 Oct 2019 21:11:59 +0000 (14:11 -0700)
19 files changed:
docs/api.rst
docs/extensions.rst
docs/faq.rst
docs/templates.rst
jinja2/__init__.py
jinja2/asyncsupport.py
jinja2/compiler.py
jinja2/environment.py
jinja2/ext.py
jinja2/filters.py
jinja2/nativetypes.py
jinja2/nodes.py
jinja2/runtime.py
jinja2/sandbox.py
jinja2/utils.py
tests/test_asyncfilters.py
tests/test_filters.py
tests/test_security.py
tests/test_tests.py

index 3f56e5ffd18b0fca5c94f1a0372e8bdec23a2583..7faf08a8bc6c50fd15ee1d430aaaeda873263b34 100644 (file)
@@ -36,8 +36,8 @@ This will create a template environment with the default settings and a
 loader that looks up the templates in the `templates` folder inside the
 `yourapplication` python package.  Different loaders are available
 and you can also write your own if you want to load templates from a
-database or other resources.  This also enables autoescaping for HTML and
-XML files.
+database or other resources.  This also enables :ref:`autoescaping` for
+HTML and XML files.
 
 To load a template from this environment you just have to call the
 :meth:`get_template` method which then returns the loaded :class:`Template`::
@@ -52,12 +52,6 @@ Using a template loader rather than passing strings to :class:`Template`
 or :meth:`Environment.from_string` has multiple advantages.  Besides being
 a lot easier to use it also enables template inheritance.
 
-.. admonition:: Notes on Autoescaping
-
-   In future versions of Jinja2 we might enable autoescaping by default
-   for security reasons.  As such you are encouraged to explicitly
-   configure autoescaping now instead of relying on the default.
-
 
 Unicode
 -------
@@ -254,44 +248,37 @@ useful if you want to dig deeper into Jinja2 or :ref:`develop extensions
     :members: disable_buffering, enable_buffering, dump
 
 
+.. _autoescaping:
+
 Autoescaping
 ------------
 
-.. versionchanged:: 2.4
-
-Jinja2 now comes with autoescaping support.  As of Jinja 2.9 the
-autoescape extension is removed and built-in.  However autoescaping is
-not yet enabled by default though this will most likely change in the
-future.  It's recommended to configure a sensible default for
-autoescaping.  This makes it possible to enable and disable autoescaping
-on a per-template basis (HTML versus text for instance).
+Autoescaping is a feature to mitigate injection attacks when rendering
+HTML and XML documents. When autoescaping is enabled, Jinja will use
+`MarkupSafe`_ to escape unsafe characters in the output of expressions,
+unless the output is marked safe. For example, if a comment contained
+``<script>alert("hello")</script>``, the tags would be rendered with
+escapes like ``&lt;script&gt;``. In a user's browser, the comment would
+display as text, rather than being interpreted as a script.
+
+Because Jinja can be used to render any type of document for many types
+of applications, not just HTML with untrusted input, autoescaping is not
+enabled by default. You should configure a sensible default based on
+your use case when creating the environment. The
+:func:`~jinja2.select_autoescape` function can be used to enable
+autoescaping for HTML templates while disabling it in text templates.
 
 .. autofunction:: jinja2.select_autoescape
 
-Here a recommended setup that enables autoescaping for templates ending
-in ``'.html'``, ``'.htm'`` and ``'.xml'`` and disabling it by default
-for all other extensions.  You can use the :func:`~jinja2.select_autoescape`
-function for this::
+You can also pass ``autoescape=True`` to enable it unconditionally, or
+pass your own function that takes the name of the template and returns
+whether it should be enabled. When writing a function, make sure to
+accept ``None`` as a name, as that will be passed for string templates.
 
-    from jinja2 import Environment, select_autoescape
-    env = Environment(autoescape=select_autoescape(['html', 'htm', 'xml']),
-                      loader=PackageLoader('mypackage'))
+Inside a template the behaviour can be temporarily changed by using
+the ``autoescape`` block, see :ref:`autoescape-overrides`.
 
-The :func:`~jinja.select_autoescape` function returns a function that
-works rougly like this::
-
-    def autoescape(template_name):
-        if template_name is None:
-            return False
-        if template_name.endswith(('.html', '.htm', '.xml'))
-
-When implementing a guessing autoescape function, make sure you also
-accept `None` as valid template name.  This will be passed when generating
-templates from strings.  You should always configure autoescaping as
-defaults in the future might change.
-
-Inside the templates the behaviour can be temporarily changed by using
-the `autoescape` block (see :ref:`autoescape-overrides`).
+.. _MarkupSafe: https://markupsafe.palletsprojects.com/
 
 
 .. _identifier-naming:
@@ -637,28 +624,14 @@ functions to a Jinja2 environment.
 
 .. autofunction:: jinja2.evalcontextfunction
 
-.. function:: escape(s)
-
-    Convert the characters ``&``, ``<``, ``>``, ``'``, and ``"`` in string `s`
-    to HTML-safe sequences.  Use this if you need to display text that might
-    contain such characters in HTML.  This function will not escaped objects
-    that do have an HTML representation such as already escaped data.
-
-    The return value is a :class:`Markup` string.
-
 .. autofunction:: jinja2.clear_caches
 
 .. autofunction:: jinja2.is_undefined
 
-.. autoclass:: jinja2.Markup([string])
-    :members: escape, unescape, striptags
-
-.. admonition:: Note
-
-    The Jinja2 :class:`Markup` class is compatible with at least Pylons and
-    Genshi.  It's expected that more template engines and framework will pick
-    up the `__html__` concept soon.
+.. autofunction:: markupsafe.escape
 
+.. autoclass:: markupsafe.Markup
+    :members: escape, unescape, striptags
 
 Exceptions
 ----------
@@ -738,7 +711,8 @@ paragraphs and marks the return value as safe HTML string if autoescaping is
 enabled::
 
     import re
-    from jinja2 import evalcontextfilter, Markup, escape
+    from jinja2 import evalcontextfilter
+    from markupsafe import Markup, escape
 
     _paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')
 
index 12c589076b097bffa852571a9e041436731c3418..821185816631abd69a908cd3b9fd4adeb5ea4669 100644 (file)
@@ -132,7 +132,7 @@ extraction tools in case you are not using Babel's.
 
 What's the big difference between standard and newstyle gettext calls?  In
 general they are less to type and less error prone.  Also if they are used
-in an autoescaping environment they better support automatic escaping.
+in an :ref:`autescaping` environment they better support automatic escaping.
 Here are some common differences between old and new calls:
 
 standard gettext:
index 743a6cbca7e9b6b43cd8ed3554f544d4faadf2c5..73d46598ec4242d75d11ad2b3c3c13dcca400d27 100644 (file)
@@ -95,7 +95,7 @@ means that you will less likely have an XSS problem it also causes a huge
 amount of extra processing in the template engine which can cause serious
 performance problems.  As Python doesn't provide a way to mark strings as
 unsafe Jinja has to hack around that limitation by providing a custom
-string class (the :class:`Markup` string) that safely interacts with safe
+string class (the :class:`~markupsafe.Markup` string) that safely interacts with safe
 and unsafe strings.
 
 With explicit escaping however the template engine doesn't have to perform
index 4f61469801146835f824e9dfa9a28a5b24aca582..fd3e39f7f7510a664fe057b491b6ab7450314914 100644 (file)
@@ -391,7 +391,7 @@ this template, it first locates the parent.  The extends tag should be the
 first tag in the template.  Everything before it is printed out normally and
 may cause confusion.  For details about this behavior and how to take
 advantage of it, see :ref:`null-master-fallback`. Also a block will always be
-filled in regardless of whether the surrounding condition is evaluated to be true 
+filled in regardless of whether the surrounding condition is evaluated to be true
 or false.
 
 The filename of the template depends on the template loader.  For example, the
@@ -527,7 +527,7 @@ When automatic escaping is enabled, everything is escaped by default except
 for values explicitly marked as safe.  Variables and expressions
 can be marked as safe either in:
 
-a. the context dictionary by the application with `MarkupSafe.Markup`, or
+a. the context dictionary by the application with :class:`markupsafe.Markup`, or
 b. the template, with the `|safe` filter
 
 The main problem with this approach is that Python itself doesn't have the
@@ -543,7 +543,7 @@ data that is marked as safe.
 
 String literals in templates with automatic escaping are considered unsafe
 because native Python strings (``str``, ``unicode``, ``basestring``) are not
-`MarkupSafe.Markup` strings with an ``__html__`` attribute.
+:class:`markupsafe.Markup` strings with an ``__html__`` attribute.
 
 .. _list-of-control-structures:
 
@@ -1672,8 +1672,8 @@ Autoescape Overrides
 
 .. versionadded:: 2.4
 
-If you want you can activate and deactivate the autoescaping from within
-the templates.
+If you want you can activate and deactivate :ref:`autoescaping` from within
+a template.
 
 Example::
 
@@ -1685,7 +1685,7 @@ Example::
         Autoescaping is inactive within this block
     {% endautoescape %}
 
-After an `endautoescape` the behavior is reverted to what it was before.
+After an ``endautoescape`` the behavior is reverted to what it was before.
 
 .. admonition:: Extension
 
index 0eaf72149965d12be441f011c2e76c047a47adef..3ce857a6f6a585db2879f15aee34506241c131aa 100644 (file)
@@ -53,9 +53,10 @@ from jinja2.exceptions import TemplateError, UndefinedError, \
 # decorators and public utilities
 from jinja2.filters import environmentfilter, contextfilter, \
      evalcontextfilter
-from jinja2.utils import Markup, escape, clear_caches, \
+from jinja2.utils import clear_caches, \
      environmentfunction, evalcontextfunction, contextfunction, \
      is_undefined, select_autoescape
+from markupsafe import Markup, escape
 
 __all__ = [
     'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
index b1e7b5ce9a27a6e069abfab9d36f80117ce6a74c..7ceddf417fe7c4d6703294aed688219c4309a907 100644 (file)
@@ -14,7 +14,9 @@ import asyncio
 import inspect
 from functools import update_wrapper
 
-from jinja2.utils import concat, internalcode, Markup
+from markupsafe import Markup
+
+from jinja2.utils import concat, internalcode
 from jinja2.environment import TemplateModule
 from jinja2.runtime import LoopContextBase, _last_iteration
 
index d534a827391aeb6f81f94c1ce5688af8d05c5505..10aed134b842efddee085f81b007cbcca5503fe0 100644 (file)
@@ -9,21 +9,22 @@
     :license: BSD, see LICENSE for more details.
 """
 from itertools import chain
-from copy import deepcopy
-from keyword import iskeyword as is_python_keyword
 from functools import update_wrapper
+from keyword import iskeyword as is_python_keyword
+
+from markupsafe import Markup, escape
+
 from jinja2 import nodes
 from jinja2.nodes import EvalContext
 from jinja2.visitor import NodeVisitor
 from jinja2.optimizer import Optimizer
 from jinja2.exceptions import TemplateAssertionError
-from jinja2.utils import Markup, concat, escape
+from jinja2.utils import concat
 from jinja2._compat import range_type, text_type, string_types, \
      iteritems, NativeStringIO, imap, izip
 from jinja2.idtracking import Symbols, VAR_LOAD_PARAMETER, \
      VAR_LOAD_RESOLVE, VAR_LOAD_ALIAS, VAR_LOAD_UNDEFINED
 
-
 operators = {
     'eq':       '==',
     'ne':       '!=',
index 549d9afab456b45032945fd47d5c2900e3797a1b..b7f8b2faade74fc17c22dc019e46983b671ef268 100644 (file)
@@ -12,6 +12,9 @@ import os
 import sys
 import weakref
 from functools import reduce, partial
+
+from markupsafe import Markup
+
 from jinja2 import nodes
 from jinja2.defaults import BLOCK_START_STRING, \
      BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
@@ -26,7 +29,7 @@ from jinja2.compiler import generate, CodeGenerator
 from jinja2.runtime import Undefined, new_context, Context
 from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \
      TemplatesNotFound, TemplateRuntimeError
-from jinja2.utils import import_string, LRUCache, Markup, missing, \
+from jinja2.utils import import_string, LRUCache, missing, \
      concat, consume, internalcode, have_async_gen
 from jinja2._compat import imap, ifilter, string_types, iteritems, \
      text_type, reraise, implements_iterator, implements_to_string, \
@@ -189,15 +192,14 @@ class Environment(object):
             ``None`` implicitly into an empty string here.
 
         `autoescape`
-            If set to ``True`` the XML/HTML autoescaping feature is enabled by
-            default.  For more details about autoescaping see
-            :class:`~jinja2.utils.Markup`.  As of Jinja 2.4 this can also
-            be a callable that is passed the template name and has to
-            return ``True`` or ``False`` depending on autoescape should be
-            enabled by default.
+            If set to ``True`` the HTML/XML autoescaping feature is
+            enabled by default. For more details about autoescaping see
+            :ref:`autoescaping`. This can also be a callable that is
+            passed the template name and returns whether autoescaping
+            should be enabled.
 
             .. versionchanged:: 2.4
-               `autoescape` can now be a function
+                Can be a function.
 
         `loader`
             The template loader for this environment.
index 0734a84f73d0ddb735a004c9e0416e018a7d50bd..b70b50b4a8e2295240ab7153be8fd4cd756bba48 100644 (file)
@@ -12,6 +12,8 @@
 """
 import re
 
+from markupsafe import Markup
+
 from jinja2 import nodes
 from jinja2.defaults import BLOCK_START_STRING, \
      BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
@@ -21,7 +23,7 @@ from jinja2.defaults import BLOCK_START_STRING, \
 from jinja2.environment import Environment
 from jinja2.runtime import concat
 from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError
-from jinja2.utils import contextfunction, import_string, Markup
+from jinja2.utils import contextfunction, import_string
 from jinja2._compat import with_metaclass, string_types, iteritems
 
 
index 267ddddaa03478ed77d640c011b8f2c0d6641d04..bcb651f5b44e0230d40c55c70c511782ac98075e 100644 (file)
@@ -12,14 +12,16 @@ import re
 import math
 import random
 import warnings
-
 from itertools import groupby, chain
 from collections import namedtuple
-from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
+
+from markupsafe import Markup, escape, soft_unicode
+
+from jinja2.utils import pformat, urlize, \
      unicode_urlencode, htmlsafe_json_dumps
 from jinja2.runtime import Undefined
 from jinja2.exceptions import FilterArgumentError
-from jinja2._compat import imap, string_types, text_type, iteritems, PY2
+from jinja2._compat import imap, string_types, text_type, iteritems
 
 
 _word_re = re.compile(r'\w+', re.UNICODE)
index fe17e4138df3f1c1d3cf8d207135c847f5d66615..eab95d614002935fdee85a3637ce85b2958fb217 100644 (file)
@@ -1,11 +1,14 @@
 import sys
 from ast import literal_eval
+
+from markupsafe import escape
+
 from itertools import islice, chain
 from jinja2 import nodes
 from jinja2._compat import text_type
 from jinja2.compiler import CodeGenerator, has_safe_repr
 from jinja2.environment import Environment, Template
-from jinja2.utils import concat, escape
+from jinja2.utils import concat
 
 
 def native_concat(nodes):
index 4d9a01ad8bb2e7b0b63ed483e7c4c34ed0a22033..801764afacb32078298db6a9799b550410bbb93b 100644 (file)
@@ -15,8 +15,9 @@
 import types
 import operator
 
+from markupsafe import Markup
+
 from collections import deque
-from jinja2.utils import Markup
 from jinja2._compat import izip, with_metaclass, text_type, PY2
 
 
index 5e313369edcb7e4fb83f7f8d6b08ef69baae24a2..c925b71e2af45282828a5a09b7d0f007ca5d23e2 100644 (file)
@@ -13,8 +13,10 @@ import sys
 from itertools import chain
 from types import MethodType
 
+from markupsafe import Markup, escape, soft_unicode
+
 from jinja2.nodes import EvalContext, _context_function_types
-from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
+from jinja2.utils import missing, concat, \
      internalcode, object_type_repr, evalcontextfunction, Namespace
 from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
      TemplateNotFound
index 08c22f4f13371376c380d1a3223121aa7f0723cd..88f83ae2640f2792d035b2115f27fd4cd99a5c97 100644 (file)
 """
 import types
 import operator
+from string import Formatter
+
+from markupsafe import Markup, EscapeFormatter
+
 from jinja2.environment import Environment
 from jinja2.exceptions import SecurityError
 from jinja2._compat import string_types, PY2, abc, range_type
-from jinja2.utils import Markup
-
-from markupsafe import EscapeFormatter
-from string import Formatter
 
 
 #: maximum number of items a range may produce
index db9c5d062d96b2de79ee17828d258c05e81ca5a7..8c5978d3491f2f895ef262e7a6cbcaaf2f37c8ba 100644 (file)
@@ -13,6 +13,9 @@ import json
 import errno
 from collections import deque
 from threading import Lock
+
+from markupsafe import Markup, escape
+
 from jinja2._compat import text_type, string_types, implements_iterator, \
      url_quote, abc
 
@@ -483,25 +486,28 @@ class LRUCache(object):
 abc.MutableMapping.register(LRUCache)
 
 
-def select_autoescape(enabled_extensions=('html', 'htm', 'xml'),
-                      disabled_extensions=(),
-                      default_for_string=True,
-                      default=False):
-    """Intelligently sets the initial value of autoescaping based on the
-    filename of the template.  This is the recommended way to configure
+def select_autoescape(
+    enabled_extensions=("html", "htm", "xml"),
+    disabled_extensions=(),
+    default_for_string=True,
+    default=False,
+):
+    """Set the initial value of autoescaping based on the name of the
+    template, case insensitive. This is the recommended way to configure
     autoescaping if you do not want to write a custom function yourself.
 
-    If you want to enable it for all templates created from strings or
-    for all templates with `.html` and `.xml` extensions::
+    The defaults will enable autoescaping only for template names ending
+    with ".html", ".htm", and ".xml", as well as templates from strings.
+
+    .. code-block:: python
 
         from jinja2 import Environment, select_autoescape
-        env = Environment(autoescape=select_autoescape(
-            enabled_extensions=('html', 'xml'),
-            default_for_string=True,
-        ))
+        env = Environment(autoescape=select_autoescape())
 
-    Example configuration to turn it on at all times except if the template
-    ends with `.txt`::
+    The following configuration enables it for all templates except if
+    the name ends with ".txt".
+
+    .. code-block:: python
 
         from jinja2 import Environment, select_autoescape
         env = Environment(autoescape=select_autoescape(
@@ -510,30 +516,36 @@ def select_autoescape(enabled_extensions=('html', 'htm', 'xml'),
             default=True,
         ))
 
-    The `enabled_extensions` is an iterable of all the extensions that
-    autoescaping should be enabled for.  Likewise `disabled_extensions` is
-    a list of all templates it should be disabled for.  If a template is
-    loaded from a string then the default from `default_for_string` is used.
-    If nothing matches then the initial value of autoescaping is set to the
-    value of `default`.
-
-    For security reasons this function operates case insensitive.
+    :param enabled_extensions: Template names ending in these extensions
+        will have autoescaping enabled. A "." is prepended to each value
+        if it's missing.
+    :param disabled_extensions: Template names ending in these
+        extensions will have autoescaping disabled. A "." is prepended
+        to each value if it's missing.
+    :param default_for_string: What to do if the template is loaded from
+        a string and doesn't have a name.
+    :param default: What to do if the name does not match any of the
+        other rules.
 
     .. versionadded:: 2.9
     """
-    enabled_patterns = tuple('.' + x.lstrip('.').lower()
-                             for x in enabled_extensions)
-    disabled_patterns = tuple('.' + x.lstrip('.').lower()
-                              for x in disabled_extensions)
+    enabled_patterns = tuple("." + x.lstrip(".").lower() for x in enabled_extensions)
+    disabled_patterns = tuple("." + x.lstrip(".").lower() for x in disabled_extensions)
+
     def autoescape(template_name):
         if template_name is None:
             return default_for_string
+
         template_name = template_name.lower()
+
         if template_name.endswith(enabled_patterns):
             return True
+
         if template_name.endswith(disabled_patterns):
             return False
+
         return default
+
     return autoescape
 
 
@@ -636,7 +648,3 @@ try:
     have_async_gen = True
 except SyntaxError:
     have_async_gen = False
-
-
-# Imported here because that's where it was in the past
-from markupsafe import Markup, escape, soft_unicode
index 162cc6d4d73fc4d92921e94054421db0d774a314..9796caa7f45d2f887beb15ed39da2c94e24f1e2d 100644 (file)
@@ -1,6 +1,8 @@
 import pytest
+
+from markupsafe import Markup
+
 from jinja2 import Environment
-from jinja2.utils import Markup
 
 
 async def make_aiter(iter):
index 8962ced30028a4dd333ed3c65c7e020a894b185a..2769e9c1a9c09429ad1340050e08c5cbb10fd14c 100644 (file)
 """
 import random
 import pytest
-from jinja2 import Markup, Environment
+
+from markupsafe import Markup
+
+from jinja2 import Environment
 from jinja2._compat import text_type, implements_to_string
 
 
index 5c8639c4efac5d940ae6fb3b74a52a2be4a161e5..6e6b2f2be021dc0765a6d53c4227473685b8ee4c 100644 (file)
 """
 import pytest
 
+from markupsafe import Markup
+
 from jinja2 import Environment
 from jinja2.sandbox import SandboxedEnvironment, \
      ImmutableSandboxedEnvironment, unsafe
-from jinja2 import Markup, escape
+from jinja2 import escape
 from jinja2.exceptions import SecurityError, TemplateSyntaxError, \
      TemplateRuntimeError
 from jinja2.nodes import EvalContext
index 84df5ea7577495ea5c76f29dfcd1416248d2b2e0..119851647201dc85b29010820ce96c1d9dc8e1ba 100644 (file)
@@ -10,7 +10,9 @@
 """
 import pytest
 
-from jinja2 import Markup, Environment
+from markupsafe import Markup
+
+from jinja2 import Environment
 
 
 @pytest.mark.test_tests