非常游戏网
如何修复Python项目中的XSS跨站脚本漏洞_通过MarkupSafe函数转义

如何修复Python项目中的XSS跨站脚本漏洞_通过MarkupSafe函数转义

2026-05-27日常编程225046

cgi.escape() 已被弃用且仅转义3个字符,漏掉引号、斜杠等XSS关键字符;手写replace链易遗漏、顺序错误、无法处理Unicode编码绕过,安全性不可靠。

为什么不能直接用 cgi.escape() 或手写替换逻辑

Python 2 的 cgi.escape() 已被弃用,Python 3 中彻底移除;它只处理 <>& 三个字符,漏掉单双引号、斜杠、括号等关键 XSS 触发点。手写 .replace() 链(比如 .replace(')顺序错乱或遗漏会引入绕过风险——例如先转义引号再转义尖括号,可能让攻击者用 "> 绕过闭合。

MarkupSafe 的默认行为是否足够安全

是的,但仅限 HTML 上下文输出。MarkupSafe.escape() 会把 <>>""''&&,覆盖全部基础 HTML 实体注入路径。但它不处理 JavaScript 字符串内插、URL 属性值、CSS 内联样式等上下文——这些必须用对应上下文的编码函数(如 json.dumps() + html.escape() 双重防护)。

Flask/Jinja2 中误用 |safe 导致的绕过

这是最常见踩坑点:开发者在模板里写 {{ user_input|safe }},以为只是“跳过自动转义”,实则完全关闭了所有 HTML 转义。哪怕你前面用 MarkupSafe.escape() 处理过,|safe 也会让结果原样输出。正确做法是——

  • 禁用所有 |safe,除非你 100% 确认该变量是服务端生成的、无用户输入成分的纯 HTML 片段
  • 确保 Jinja2 的 autoescape 默认开启(Flask 默认已启用)
  • 若需动态拼 HTML,用 MarkupSafe.Markup() 显式标记可信内容,而非依赖过滤器

非 HTML 输出场景仍需额外处理

比如把用户数据塞进 标签内渲染为 JS 变量:

稿定在线PS

PS软件网页版

  const username = "{{ user_input }}"; // ❌ 危险!即使 escape 过,也可能破坏 JS 语法

应改用:

  const username = {{ user_input | tojson | safe }}; // ✅ Jinja2 tojson 进行 JSON 编码 + HTML 转义双重保护

或者手动组合:

  • 先用 json.dumps(user_input, ensure_ascii=False) 得到合法 JSON 字符串
  • 再用 MarkupSafe.escape() 转义 HTML 特殊字符(防止 JSON 字符串本身含
  • 最终拼入 标签时确保引号匹配、无未闭合结构

真正难的不是转义本身,而是识别输出所处的嵌套上下文——HTML 属性、JS 字符串、URL 参数、CSS 值,每个都需要不同策略。漏掉一个上下文,就等于留了一扇没锁的门。