【发布时间】: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