如何使用Jinja2转义HTML,以便它可以在JavaScript(jQuery)中用作字符串?
如果我使用Django的模板系统,我可以写:
$("#mydiv").append("{{ html_string|escapejs }}");
Django的|escapejs
filter会逃避html_string
中的内容(例如引号,特殊字符),这可能会破坏此代码块的预期用途,但Jinja2似乎没有等效的过滤器(我错了)这里吗?)。
有没有比从Django复制/粘贴代码更清晰的解决方案?
答案 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是str
或unicode
。
答案 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 %}