沙盒

Jinja2 沙箱用于为不信任的代码求值。 访问不安全的属性和方法是被禁止的。

假定在默认配置中 env 是一个 SandboxedEnvironment 实例,下面的代码展示 了它如何工作:

>>> env.from_string("{{ func.func_code }}").render(func=lambda:None)
u''
>>> env.from_string("{{ func.func_code.do_something }}").render(func=lambda:None)
Traceback (most recent call last):
  ...
SecurityError: access to attribute 'func_code' of 'function' object is unsafe.

API

class jinja2.sandbox.SandboxedEnvironment([options])

沙箱环境。它像常规环境一样工作,但是告诉编译器生成沙盒代码。此外,此环境的子类可能会覆盖告知运行时哪些属性或函数可安全访问的方法。

如果模板尝试访问不安全代码,则会引发SecurityError然而,在呈现期间也可能发生其他异常,因此调用者必须确保捕获所有异常。

call_binop(context, operator, left, right)

对于截获的二进制运算符调用(intercepted_binops()),将执行此函数,而不是内置运算符。这可以用于微调某些运算符的行为。

版本2.6中的新功能。

call_unop(context, operator, arg)

对于拦截的一元运算符调用(intercepted_unops()),将执行此函数,而不是内置运算符。这可以用于微调某些运算符的行为。

版本2.6中的新功能。

default_binop_table = {'+': <built-in function add>, '/': <built-in function truediv>, '**': <built-in function pow>, '-': <built-in function sub>, '*': <built-in function mul>, '%': <built-in function mod>, '//': <built-in function floordiv>}

默认回调表为二进制运算符。此副本可在沙箱环境的每个实例(binop_table)上提供

default_unop_table = {'-': <built-in function neg>, '+': <built-in function pos>}

默认回调表为一元运算符。此副本可在沙箱环境的每个实例(unop_table)上提供

intercepted_binops = frozenset()

应该被拦截的一组二进制运算符。添加到此集合的每个运算符(默认为空)被委托给将执行运算符的call_binop()方法。默认操作符回调由binop_table指定。

The following binary operators are interceptable: //, %, +, *, -, /, and **

操作员表的默认操作对应于内置函数。拦截的调用总是比本地操作符调用慢,所以确保只拦截那些你感兴趣的。

版本2.6中的新功能。

intercepted_unops = frozenset()

应该拦截一组一元运算符。添加到此集合中的每个运算符(默认为空)被委托给将执行运算符的call_unop()方法。默认操作符回调由unop_table指定。

以下一元运算符是可拦截的:+-

操作员表的默认操作对应于内置函数。拦截的调用总是比本地操作符调用慢,所以确保只拦截那些你感兴趣的。

版本2.6中的新功能。

is_safe_attribute(obj, attr, value)

沙盒环境将调用此方法来检查对象的属性是否安全访问。默认情况下,以下划线开头的所有属性都被认为是私有的,以及由is_internal_attribute()函数返回的内部python对象的特殊属性。

is_safe_callable(obj)

检查对象是否可安全调用。默认情况下,一个函数被认为是安全的,除非unsafe_callable属性存在并且为True。覆盖此方法以更改行为,但这不会影响此模块中的unsafe装饰器。

class jinja2.sandbox.ImmutableSandboxedEnvironment([options])

Works exactly like the regular SandboxedEnvironment but does not permit modifications on the builtin mutable objects list, set, and dict by using the modifies_known_mutable() function.

exception jinja2.sandbox.SecurityError(message=None)

在模板尝试执行某些不安全操作(如果沙箱已启用)时引发。

jinja2.sandbox.unsafe(f)

将函数或方法标记为不安全。

@unsafe
def delete(self):
    pass
jinja2.sandbox.is_internal_attribute(obj, attr)

测试给定的属性是否是内部python属性。例如,此函数为python对象的func_code属性返回True如果环境方法is_safe_attribute()被覆盖,这将非常有用。

>>> from jinja2.sandbox import is_internal_attribute
>>> is_internal_attribute(str, "mro")
True
>>> is_internal_attribute(str, "upper")
False
jinja2.sandbox.modifies_known_mutable(obj, attr)

此函数检查内置可变对象(list,dict,set或deque)上的属性是否会被调用。它还支持对象的“用户”转换(sets.SetUserDict。*等)和Python 2.6以上的抽象基类MutableSetMutableMappingMutableSequence

>>> modifies_known_mutable({}, "clear")
True
>>> modifies_known_mutable({}, "keys")
False
>>> modifies_known_mutable([], "append")
True
>>> modifies_known_mutable([], "index")
False

如果使用不受支持的对象(如unicode)调用,则返回False

>>> modifies_known_mutable("foo", "upper")
False

注意

Jinja2 沙箱自己并没有彻底解决安全问题。 特别是对 web 应用,你必须晓得用户 可能用任意 HTML 来创建模板,所以保证他们不通过注入 JavaScript 或其它更多 方法来互相损害至关重要(如果你在同一个服务 器上运行多用户)。

同样,沙箱的好处取决于配置。 我们强烈建议只向模板传递非共享资源,并 且使用某种属性白名单。

也请记住,模板会抛出运行时或编译期错误,确保捕获它们。

操作符拦截

版本2.6中的新功能。

为了性能最大化, Jinja2 会让运算符直接条用类型特定的回调方法。 这意味着, 通过重载 Environment.call() 来拦截是不可能的。 此外,由于运算符的工作 方式,把运算符转换为特殊方法不总是直接可行的。 比如为了分类,至少一个特殊 方法存在。

在 Jinja 2.6 中,开始支持显式的运算符拦截。 必要时也可以用于自定义的特定 运算符。 为了拦截运算符,需要覆写 SandboxedEnvironment.intercepted_binops 属性。 当需要拦截的运算符 被添加到这个集合, Jinja2 会生成调用 SandboxedEnvironment.call_binop() 函数的字节码。 对于一元运算符, 必须替代地使用 unary 属性和方法。

SandboxedEnvironment.call_binop 的默认实现会使用 SandboxedEnvironment.binop_table 来把运算符标号翻译成执行默认 运算符行为的回调。

这个例子展示了幂( ** )操作符可以在 Jinja2 中禁用:

from jinja2.sandbox import SandboxedEnvironment


class MyEnvironment(SandboxedEnvironment):
    intercepted_binops = frozenset(['**'])

    def call_binop(self, context, operator, left, right):
        if operator == '**':
            return self.undefined('the power operator is unavailable')
        return SandboxedEnvironment.call_binop(self, context,
                                               operator, left, right)

确保始终调入 super 方法,即使你不拦截这个调用。 Jinja2 内部会调用 这个方法来对表达式求值。