Python 如何防止Jinja2模板中的循环{%include%}调用

Python 如何防止Jinja2模板中的循环{%include%}调用,python,django,template-engine,jinja2,circular-reference,Python,Django,Template Engine,Jinja2,Circular Reference,我有一个Django SaaS应用程序,用户可以创建自己的Jinja2模板(在一个非常沙盒的环境中,对于那些畏缩的人来说),并将其保存到数据库中。我有一个template\u type字段,指出给定模板是“包含”还是“完整模板”(完整模板当然可以包含“包含”)。问题是,用户可能将{%include“foo”%}放入名为“bar”的模板中,并将{%include“bar”}放入“foo”模板中,从而导致运行时错误:最大递归深度超过了类型的情况,这对性能不利 是否有一种很好的方法来处理这种不包含验证

我有一个Django SaaS应用程序,用户可以创建自己的Jinja2模板(在一个非常沙盒的环境中,对于那些畏缩的人来说),并将其保存到数据库中。我有一个
template\u type
字段,指出给定模板是“包含”还是“完整模板”(完整模板当然可以包含“包含”)。问题是,用户可能将
{%include“foo”%}
放入名为
“bar”
的模板中,并将
{%include“bar”}
放入
“foo”
模板中,从而导致
运行时错误:最大递归深度超过了
类型的情况,这对性能不利

是否有一种很好的方法来处理这种不包含验证regexp(例如,
r'\{%\s+include'
)的情况,在用户模板创建期间检查include(“确保递归导入永远不会进入数据库,否则您的服务器将丢失”不会与我发生冲突)

我失败的尝试 我首先使用一个只包含用户“包含”的自定义加载程序:


这样做的问题是,我基本上阻止了自己利用Jinja2的优势,这显然要求所有模板都可用于
加载(…
调用,调用
获取源代码(…

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

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

您能否在创建时使用测试数据执行新模板,捕获RumtimeError,然后向用户抛出适当的错误消息?并将递归限制临时设置为较低的值(请参阅)?不过,这并不包括条件包含。你有没有遇到过关于Jinja2沙盒功能的好指南?我将开始做与你完全相同的事情,我发现的只是官方文档和关于堆栈溢出的3个问题。@Jon-我刚刚浏览了一遍。你需要做的是使用最有限的沙盒类,然后然后重写“is-attribute-safe”和“is-safe-callable”方法(不记得实际的方法名),以限制尝试访问任何值不是内置类型(或某些预期类型)的属性,以及限制访问没有“is-safe”的调用方法属性设置为true。再加上确保暴露的对象上没有具有危险副作用的
@property
s,这将保护你的应用程序。听起来不错。谢谢。我将在本周对此进行深入研究。如果你看过SailThru的Zephyr模板语言,这正是我想要实现的。我很确定进入沙盒的每个对象都会被转换成一个类似JSON的对象,然后我会通过一个实用对象来允许有限的函数子集。虽然我还不知道如何做到这一点。谢谢!顺便问一下,使用
parse
from_string
有何不同,或者它们只是来自不同的版本?parse呢不执行实际包含?也许我理解你的问题。从字符串加载模板。Parse为你提供一个抽象的sytax树(AST)。在我的代码中:每个都提供包含标记值。我使用包含标记动态包含CMS中的图像、PDF、URL、css、js、html和txt模板,并在保存模板时使用解析器验证引用文件是否存在。
    ast = env.parse(template_text)
    for each in meta.find_referenced_templates(ast) :        # find the (% includes %}