bigywater.tech
Flask · 123

XSS 防护

Jinja2 的自动转义到底保护哪些位置?哪些位置它不管?|safe、Markup、属性不加引号、JS 上下文、href 各自会怎样?这篇用 9 种输出位置的攻击载荷,在真实的 Chrome 里逐个看脚本到底有没有执行。

9 种
实验的输出位置,其中 5 种被攻击成功
|tojson
JS 上下文里唯一安全的输出方式
javascript:
自动转义不会拦截的 URL 协议

9 种输出位置

实测 · 本机执行输出
  正文里 {{ q }}(自动转义)                  载荷 '<script>window.__x=1</script>'
      服务端输出的 HTML: <div>&lt;script&gt;window.__x=1&lt;/script&gt;</div>
      浏览器结果:没有执行
  正文里 {{ q|safe }}                   载荷 '<script>window.__x=1</script>'
      服务端输出的 HTML: <div><script>window.__x=1</script></div>
      浏览器结果:XSS 执行了
  属性不加引号 value={{ q }}               载荷 'x onfocus=window.__x=1 autofocus'
      服务端输出的 HTML: <input value=x onfocus=window.__x=1 autofocus>
      浏览器结果:XSS 执行了
  属性加引号 value="{{ q }}"              载荷 '" onfocus="window.__x=1" autofocus'
      服务端输出的 HTML: <input value="&#34; onfocus=&#34;window.__x=1&#34; autofocus=&#34;">
      浏览器结果:没有执行
  脚本里的字符串 "{{ q }}"                  载荷 '";window.__x=1;//'
      服务端输出的 HTML: <script>var name = "&#34;;window.__x=1;//";</script>
      浏览器结果:没有执行
  脚本里直接 {{ q }}(没有引号)                载荷 '1;window.__x=1'
      服务端输出的 HTML: <script>var n = 1;window.__x=1;</script>
      浏览器结果:XSS 执行了
  脚本里 {{ q|tojson }}                 载荷 '1;window.__x=1'
      服务端输出的 HTML: <script>var n = "1;window.__x=1";</script>
      浏览器结果:没有执行
  href="{{ q }}"(页面自动点击链接)           载荷 'javascript:window.__x=1'
      服务端输出的 HTML: <a id=l href="javascript:window.__x=1">click</a><script>document.getElementById("l").click()</script>
      浏览器结果:XSS 执行了
  Markup("<b>" + q + "</b>") 拼接后输出   载荷 '<img src=x onerror=window.__x=1>'
      服务端输出的 HTML: <div><b><img src=x onerror=window.__x=1></b></div>
      浏览器结果:XSS 执行了

上一篇:CSRF 防护;下一篇:SQL Injection 与参数化查询。

浏览器是本机的 Google Chrome 无头模式。「脚本是否执行」的判断是载荷里把 window.__x 置位、页面末尾读取它,没有弹窗。

分步演示

XSS 防护
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。本机 Google Chrome(无头模式)、MarkupSafe
    • 没有验证:CSP 响应头对这些攻击的缓解效果(见第 133 篇)、DOM 型 XSS(前端 JS 里 innerHTML)、富文本清洗库(bleach 或 nh3)的效果、模板之外的响应(如直接返回字符串的视图的 Content-Type 与 XSS)、Markdown 渲染后的 XSS
    京ICP备2026067502号-1京公网安备11010502063487号