【问题标题】:How can I prevent circular {% include %} calls in Jinja2 templates如何防止 Jinja2 模板中的循环 {% include %} 调用
【发布时间】:2012-11-13 05:30:08
【问题描述】:

我有一个 Django SaaS 应用程序,用户创建了自己的 Jinja2 模板(在一个非常沙盒环境中,对于那些只是畏缩的人),这些模板被保存到数据库中。我有一个template_type 字段,注意给定模板是“包含”还是“完整模板”(完整模板当然可以包含“包含”)。问题是用户可以将{% include "foo" %} 放入名为"bar" 的模板中,并将{% include "bar" %} 放入"foo" 模板中,从而导致RuntimeError: maximum recursion depth exceeded 类型的情况,这对性能不利。

有没有一种很好的方法来处理这种情况,它不包括验证正则表达式(例如,r'\{%\s+include')在用户模板创建期间检查包含(“确保递归导入永远不会进入数据库,或者你的server will asplode" 不适合我)。

我的失败尝试

我首先使用了一个自定义加载器,它只包含用户的“包含”::

def get_source(self, environment, template):
    """
    Returns the source of the template or raises ``TemplateNotFound``.
    This loader is for use with an environment which intends to load each
    template from a string, since only includes are loaded from here.
    """
    try:
        template = self.snippets[template]
    except KeyError:
        raise jinja2.TemplateNotFound(
            template, message=u'Snippet "{s}" was not found'.format(s=template)
        )
    else:
        source = template['source']
        return (source, None, lambda: True)

这样做的问题是,我基本上阻止了自己利用 Jinja2 的 Bytecode Cache,这显然要求所有模板都可用于 load(... 调用,而后者又调用 @ 987654332@.

【问题讨论】:

  • 您能否在创建时使用测试数据执行新模板,捕获 RumtimeError,然后向用户抛出适当的错误消息?并暂时将递归限制设置为较低的值(参见stackoverflow.com/questions/3323001/maximum-recursion-depth)?但是,这并没有捕获条件包含。
  • 您是否遇到过有关 Jinja2 沙盒功能的优秀指南?我即将开始做和你一样的事情,我发现的只是官方文档和 Stack Overflow 上的 3 个问题。
  • @Jon - 我刚刚疏通了它。您需要做的是使用最有限的沙箱类,然后覆盖“属性安全”和“可安全调用”方法(不记得实际方法名称)以限制尝试访问其值不是的任何属性内置类型(或某些预期类型),以及限制对未将某些“安全”属性设置为 true 的调用方法的访问。这一点,再加上确保您的暴露对象上没有带有危险副作用的@propertys,将保护您的应用程序。
  • 听起来不错。谢谢。这周我将深入研究它。如果您曾经看过 SailThru 的 Zephyr 模板语言,那几乎就是我想要实现的。我很确定进入沙盒的每个对象都将被转换为类似 JSON 的对象,然后我将通过实用程序对象允许有限的函数子集。虽然我还不知道该怎么做。

标签: python django template-engine jinja2 circular-reference


【解决方案1】:

要解析模板并检查包含,我使用以下代码:

    ast = env.parse(template_text)
    for each in meta.find_referenced_templates(ast) :        # find the (% includes %}

【讨论】:

  • 谢谢!顺便说一句,使用parsefrom_string 有何不同,或者它们只是来自不同的版本? parse 不执行实际的包含吗?
  • 也许我明白你的问题。 from_string 加载模板。 Parse 为您提供了一个抽象语法树 (AST)。在我的代码中:每个都为您提供包含标记值。我使用包含标签从 CMS 和解析器中动态包含图像、pdf、url、css、js、html 和 txt 模板,以在保存模板时验证引用的文件是否存在。
猜你喜欢
  • 1970-01-01
  • 2011-09-20
  • 1970-01-01
  • 1970-01-01
  • 2019-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多