沙箱

JJJA沙箱可用于呈现不受信任的模板。对属性、方法调用、运算符、变异数据结构和字符串格式的访问可以被拦截和禁止。

>>> from jinja2.sandbox import SandboxedEnvironment
>>> env = SandboxedEnvironment()
>>> func = lambda: "Hello, Sandbox!"
>>> env.from_string("{{ func() }}").render(func=func)
'Hello, Sandbox!'
>>> env.from_string("{{ func.__code__.co_code }}").render(func=func)
Traceback (most recent call last):
  ...
SecurityError: access to attribute '__code__' of 'function' object is unsafe.

例如,沙箱环境可用于允许内部报告系统的用户创建自定义电子邮件。您将记录模板中可用的数据,然后用户将使用该信息编写模板。您的代码将生成报表数据,并将其传递给用户的沙箱模板以呈现。

安全注意事项

沙箱本身并不是完美安全的解决方案。在使用沙箱时请牢记这些事项。

模板在编译或呈现时仍会引发错误。您的代码应该尝试捕获错误,而不是崩溃。

可以构造一个相对较小的模板来呈现非常大量的输出,这可能对应于CPU或内存的高使用率。您应该在运行应用程序时限制CPU和内存等资源,以缓解这一问题。

JJJA只呈现文本,它不理解,例如,JavaScript代码。根据渲染模板的使用方式,您可能需要执行其他后处理以限制输出。

只传递与模板相关的数据。避免传递具有副作用的方法的全局数据或对象。默认情况下,沙箱阻止私有和内部属性访问。您可以覆盖 is_safe_attribute() 以进一步限制属性访问。用来修饰方法 unsafe() 以防止在将对象作为数据传递时从模板调用它们。使用 ImmutableSandboxedEnvironment 要防止修改列表和词典,请执行以下操作。

API

class jinja2.sandbox.SandboxedEnvironment([options])

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

如果模板试图访问不安全的代码A SecurityError 提高了。但是,在呈现期间也可能发生其他异常,因此调用方必须确保捕获所有异常。

参数:
  • args (Any) --

  • kwargs (Any) --

call_binop(context, operator, left, right)

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

Changelog

在 2.6 版本加入.

参数:
返回类型:

Any

call_unop(context, operator, arg)

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

Changelog

在 2.6 版本加入.

参数:
返回类型:

Any

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 .

以下二进制运算符是可拦截的: //, %, +, *, -, /, and `` **

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

Changelog

在 2.6 版本加入.

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

应截取的一元运算符集。添加到此集合中的每个运算符(默认为空)都委托给 call_unop() 将执行运算符的方法。默认的运算符回调由 unop_table .

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

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

Changelog

在 2.6 版本加入.

is_safe_attribute(obj, attr, value)

沙盒环境将调用此方法以检查对象的属性是否可以安全访问。默认情况下,所有以下划线开头的属性都被视为私有属性,以及由 is_internal_attribute() 功能。

参数:
返回类型:

bool

is_safe_callable(obj)

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

这也承认Django约定设置 func.alters_data = True

参数:

obj (Any) --

返回类型:

bool

class jinja2.sandbox.ImmutableSandboxedEnvironment([options])

和普通的一样 SandboxedEnvironment 但不允许对内置可变对象进行修改 listsetdict 通过使用 modifies_known_mutable() 功能。

参数:
  • args (Any) --

  • kwargs (Any) --

exception jinja2.sandbox.SecurityError(message=None)

如果模板尝试执行不安全的操作(如果启用了沙盒),则引发。

参数:

message (str | None) --

返回类型:

None

jinja2.sandbox.unsafe(f)

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

参数:

f (F) --

返回类型:

F

jinja2.sandbox.is_internal_attribute(obj, attr)

测试给定的属性是否为内部python属性。例如,此函数返回 True 对于 func_code python对象的属性。如果环境方法 is_safe_attribute() 被重写。

>>> from jinja2.sandbox import is_internal_attribute
>>> is_internal_attribute(str, "mro")
True
>>> is_internal_attribute(str, "upper")
False
参数:
返回类型:

bool

jinja2.sandbox.modifies_known_mutable(obj, attr)

此函数检查内置可变对象(list、dict、set或deque)上的属性或相应的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
参数:
返回类型:

bool

运算符拦截

为了提高性能,JJJA在编译时直接输出操作符。这意味着无法通过重写来拦截操作员行为 SandboxEnvironment.call 默认情况下,因为运算符特殊方法是由Python解释器处理的,根据运算符的使用,它可能并不只对应于一个方法。

沙箱可以指示编译器输出函数来截取某些操作符。超覆 SandboxedEnvironment.intercepted_binopsSandboxedEnvironment.intercepted_unops 带有您要截取的运算符符号。编译器将用调用 SandboxedEnvironment.call_binop()SandboxedEnvironment.call_unop() 取而代之的是。这些方法的默认实现将使用 SandboxedEnvironment.binop_tableSandboxedEnvironment.unop_table 将运算符符号转换为 operator 功能。

例如,权力 (** )操作员可以禁用:

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 super().call_binop(self, context, operator, left, right)