沙盒 — Jinja 文档

来自菜鸟教程
Jinja/docs/2.9.x/sandbox
跳转至:导航、​搜索

沙盒

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.

应用程序接口

class jinja2.sandbox.SandboxedEnvironment([options])

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

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

call_binop(context: jinja2.runtime.Context, operator: str, left: Any, right: Any) Any

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

2.6 版中的新功能。

call_unop(context: jinja2.runtime.Context, operator: str, arg: Any) Any

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

2.6 版中的新功能。

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

二元运算符的默认回调表。 此副本在沙盒环境的每个实例上都可用,名称为 binop_table

default_unop_table: Dict[str, Callable[[Any], Any]] = {'+': <built-in function pos>, '-': <built-in function neg>}

一元运算符的默认回调表。 此副本在沙盒环境的每个实例上都可用,名称为 unop_table

intercepted_binops: FrozenSet[str] = frozenset({})

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

以下二元运算符是可截取的://%+*-/**

运算符表的默认操作对应于内置函数。 拦截的调用总是比本地操作符调用慢,因此请确保只拦截您感兴趣的调用。

2.6 版中的新功能。

intercepted_unops: FrozenSet[str] = frozenset({})

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

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

运算符表的默认操作对应于内置函数。 拦截的调用总是比本地操作符调用慢,因此请确保只拦截您感兴趣的调用。

2.6 版中的新功能。

is_safe_attribute(obj: Any, attr: str, value: Any) bool

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

is_safe_callable(obj: Any) bool

检查对象是否可安全调用。 默认情况下,callables 被认为是安全的,除非用 unsafe() 修饰。

这也认可了设置 func.alters_data = True 的 Django 约定。

class jinja2.sandbox.ImmutableSandboxedEnvironment([options])
与常规的 SandboxedEnvironment 完全一样,但不允许使用 list、set 和 dict 修改内置可变对象X186X]modifies_known_mutable() 函数。
exception jinja2.sandbox.SecurityError(message: Optional[str] = None)
如果启用了沙箱,模板尝试做一些不安全的事情时引发。
jinja2.sandbox.unsafe(f: jinja2.sandbox.F) jinja2.sandbox.F
将函数或方法标记为不安全。
jinja2.sandbox.is_internal_attribute(obj: Any, attr: str) bool

测试给定的属性是否是内部 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: Any, attr: str) bool

此函数检查内置可变对象(列表、字典、集合或双端队列)或相应 ABC 上的属性是否会在调用时修改它。

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

如果使用不受支持的对象调用,则返回 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() 函数的字节码。 对于一元运算符,必须改用 一元 属性和方法。

SandboxedEnvironment.call_binop 的默认实现将使用 SandboxedEnvironment.binop_table 将运算符符号转换为执行默认运算符行为的回调。

这个例子展示了如何在 Jinja2 中禁用 power (**) 运算符:

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 可能会在内部调用该方法来评估表达式。