使用Jinja2转义JavaScript的字符串?

时间:2012-09-09 14:12:58

标签: javascript python jinja2

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

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

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

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

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

6 个答案:

答案 0 :(得分: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是strunicode

答案 1 :(得分: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}})

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

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

重要提示:请给@ medmunds提供以下精明评论的提示,提醒我们json.dumps不是XSS安全的。 IOW,您不希望在面向互联网的生产服务器中使用它。建议写一个safer json escape routine(或者偷django的 - 抱歉OP,我知道你希望避免这种情况)并调用它而不是使用json.dumps。

答案 2 :(得分:3)

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

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

答案 3 :(得分: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序列化的东西

答案 4 :(得分: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))

用法完全相同。

答案 5 :(得分:-1)

你也可以使用jinja2的autoescape。因此,例如,您可以在Python中将自动视图添加到jinja2环境中:

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

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

的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 %}