Jinja2默认防护有效,XSS主因是开发者误用|safe、字符串拼接、JS上下文未用|tojson、URL未|urlencode及忽略富文本过滤。

绝大多数XSS漏洞不是Jinja2没防护,而是你亲手关掉了它、绕过了它,或用错了上下文。
别在模板里用 |safe 放行用户输入
Jinja2默认对 {{ variable }} 做HTML转义,但|safe会跳过这层保护——只要变量含<script>,它就真执行。
- 错误写法:
{{ user_bio|safe }}→ 用户填<img onerror="fetch('/steal', {method:'POST', body:document.cookie})">即中招 - 正确写法:
{{ user_bio }}→ 自动转义为<img onerror="..." alt="如何修复Python Web应用中因不当使用Jinja2导致的XSS漏洞?" >,纯文本显示 - 唯一例外:富文本内容必须用
|safe时,先过bleach.clean()白名单过滤,禁用script、on*等危险标签和属性
禁止用Python字符串拼接生成HTML
绕过模板引擎,等于放弃所有自动转义。哪怕只拼一个div,风险也拉满。
- 危险示例:
return f"<h3>Hello, {name}</h3>"→ name为<svg onload=alert(1)>直接触发 - 安全做法:始终走
render_template(),模板内用{{ name }} - 若必须拼(如发邮件),先调
html.escape(name),再拼接
JS上下文必须用 |tojson,不能直接插变量
HTML转义对<script>块或onclick属性无效。单引号、反斜杠、</script>都会破坏语法结构,导致执行。
立即学习“Python免费学习笔记(深入)”;
- 错误写法:
<script>var msg = "{{ user_input }}";</script> - 正确写法:
<script>var msg = {{ user_input | tojson }};</script>→ 输出"<hello&world>"这种合法JSON字符串 - 属性值同理:避免
<button onclick="do('{{ action }}')">,改用<button data-action="{{ action | e }}">+ JS读取
URL参数必须走 |urlencode,别手拼
URL里空格、中文、&、=不编码,轻则400报错,重则被注入javascript:alert(1)伪协议。
- 错误:
<a href="/search?q={{ keyword }}">→ keyword为foo" onclick="alert(1),变成<a href="/search?q=foo" onclick="alert(1)"> - 正确:
<a href="/search?q={{ keyword | urlencode }}"> - 多参数更简单:
<a href="/search?{{ {'q': q, 'page': 1} | urlencode }}">→ 自动拼成/search?q=xxx&page=1
真正容易忽略的是那些“不像代码”的输入:昵称里的onmouseover=alert(1)、头像URL中的data:image/svg+xml,<svg onload=>——它们不会被|e拦住,得靠CSP策略+输入白名单双保险。


















