22

如何使用 Jinja2 转义 HTML,以便它可以用作 JavaScript (jQuery) 中的字符串?

如果我使用 Django 的模板系统,我可以这样写:

$("#mydiv").append("{{ html_string|escapejs }}");

Django 的|escapejs过滤器会转义html_string(例如引号、特殊字符)中可能破坏此代码块的预期用途的内容,但 Jinja2 似乎没有等效的过滤器(我在这里错了吗?)。

有没有比从 Django 复制/粘贴代码更干净的解决方案?

4

6 回答 6

19

Jinja2 有很好的过滤器tojson。如果从字符串生成 json,它将生成用双引号“”括起来的字符串。您可以在 javascript 中安全地使用它。而且您不需要自己加上引号。

$("#mydiv").append({{ html_string|tojson }});
于 2018-11-18T07:20:20.297 回答
15

这是一个escapejs过滤器,基于 Django 的过滤器,我编写用于 Jinja2 模板:

_js_escapes = {
        '\\': '\\u005C',
        '\'': '\\u0027',
        '"': '\\u0022',
        '>': '\\u003E',
        '<': '\\u003C',
        '&': '\\u0026',
        '=': '\\u003D',
        '-': '\\u002D',
        ';': '\\u003B',
        u'\u2028': '\\u2028',
        u'\u2029': '\\u2029'
}
# Escape every ASCII character with a value less than 32.
_js_escapes.update(('%c' % z, '\\u%04X' % z) for z in xrange(32))
def jinja2_escapejs_filter(value):
        retval = []
        for letter in value:
                if _js_escapes.has_key(letter):
                        retval.append(_js_escapes[letter])
                else:
                        retval.append(letter)

        return jinja2.Markup("".join(retval))
JINJA_ENVIRONMENT.filters['escapejs'] = jinja2_escapejs_filter

模板中的安全用法示例:

<script type="text/javascript">
<!--
var variableName = "{{ variableName | escapejs }}";
…
//-->
</script>

当 variableName 是 astr或时unicode

于 2013-09-19T17:07:29.080 回答
9

去年我也遇到过类似的问题。不确定您是否使用bottle,但我的解决方案看起来像这样。

import json

def escapejs(val):
    return json.dumps(str(val)) # *but see [Important Note] below to be safe

@app.route('/foo')
def foo():
    return bottle.jinja2_template('foo', template_settings={'filters': {'escapejs': escapejs}})

(我将 dict 包装template_settings在一个辅助函数中,因为我在任何地方都使用它,但在这个例子中我保持简单。)

不幸的是,它不像内置的 jinja2 过滤器那么简单,但我能够愉快地使用它——特别是考虑到我还需要添加其他几个自定义过滤器。

重要提示:向@medmunds 致敬,感谢他在下面的精明评论,提醒我们 json.dumps 不是 XSS 安全的。IOW,您不希望在面向 Internet 的生产服务器中使用它。建议是编写一个更安全的 json 转义例程(或窃取 django 的——抱歉 OP,我知道您希望避免这种情况)并调用它而不是使用 json.dumps。

于 2012-09-09T14:40:09.010 回答
1

我刚刚研究了这个问题,我的解决方案是定义一个过滤器:

from flask import Flask, Markup
app = Flask(__name__)
app.jinja_env.filters['json'] = lambda v: Markup(json.dumps(v))

并在模板中:

<script>
var myvar = {{myvar|json}} ;
</script>

这有一个很好的功能,即myvar可以是任何可以被 JSON 序列化的东西

于 2013-10-09T10:11:12.897 回答
0

基于@tometzky,这里是我的 Python 3 版本:

_js_escapes = {
        '\\': '\\u005C',
        '\'': '\\u0027',
        '"': '\\u0022',
        '>': '\\u003E',
        '<': '\\u003C',
        '&': '\\u0026',
        '=': '\\u003D',
        '-': '\\u002D',
        ';': '\\u003B',
        u'\u2028': '\\u2028',
        u'\u2029': '\\u2029'
}
# Escape every ASCII character with a value less than 32.
_js_escapes.update(('%c' % z, '\\u%04X' % z) for z in range(32))

@register.filter
def escapejs(value):
    return jinja2.Markup("".join(_js_escapes.get(l, l) for l in value))

用法完全一样。

于 2019-06-27T14:11:09.160 回答
-1

您也可以使用 jinja2 的autoescape. 因此,例如,您可以在 Python 中将自动转义添加到您的 jinja2 环境中:

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
    autoescape=True)

或者,您可以使用 Jinja 2.4 中添加的 Autoescape 扩展来更好地控制在 HTML 中使用自动转义的位置。更多关于此信息和示例(在 Google App Engine 中)在这里

Python:

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
    extensions=['jinja2.ext.autoescape'])

HTML:

{% autoescape true %}
    <html>
        <body>
            {{ IWillBeEscaped }}
        </body>
    </html>
{% endautoescape %}
于 2013-07-06T23:05:05.123 回答