必须转义的只有5个字符:&、<、>、"、';其中&最危险,所有HTML实体都以它开头,未转义会导致解析错误或截断;<和>在标签中生效,"和'仅在属性值内生效;innerHTML插入用户输入前必须转义,否则可能执行脚本。

哪些字符必须转义?只这5个,多一个都是错的
只有 &、、<code>>、"、' 这五个字符在 HTML 中具有语法意义,必须转义。其他字符(比如中文、emoji、©、→)只要页面声明了 <meta charset="utf-8">,就无需额外转义。
常见错误包括:对空格、换行、中文全角符号做无谓转义;或漏掉 & ——它最危险,因为所有实体都以它开头,未转义的 & 可能导致 &xyz 类解析失败,甚至截断后续内容。
-
&必须转为&,哪怕它后面不跟字母(如price: 10&20→price: 10&20) 和 <code>>在纯文本内容里有时“看起来”没出错,但混入用户输入(如搜索词react <div>)就会触发标签注入 <li> <code>"和'只在属性值内生效;若用textContent或 JS 字符串拼接,它们不构成风险- 简单单值:用
document.createElement('div').textContent = str,再取.innerHTML——它内部调用的是 DOM 的标准转义机制 - 批量/高频场景:用
DOMPurify.sanitize()(白名单过滤)或服务端预处理,避免反复创建 DOM 节点 - 绝对不要用
str.replace(/, '<')这类不完整替换,漏掉&就等于开门揖盗 - 顺序错误:先替换
&再替换,会导致 <code><变成(双重转义) - 遗漏边界:没加
re.escape()或锚点,可能误匹配 URL 中的& - 性能差异:内置函数用 C 实现,比纯 Python 正则快 3–5 倍,尤其在长文本中
- 用了
|safe或|raw却没确认来源可信(比如直接传入用户提交的富文本) - 在 JS 字符串中拼接模板变量:
var msg = "{{ user_input }}";—— 这里"和\会破坏 JS 语法,需用|tojson(Jinja2)或|json_script(Django) - URL 参数拼接:
<a href="/search?q={{ keyword }}">——&和=在 query string 里要 urlencode,不能只靠 HTML 转义
innerHTML 插入前不转义 = 直接执行脚本
只要用 innerHTML 赋值,且内容含用户输入(哪怕只是昵称、评论、URL 参数),就必须先转义。浏览器会把字符串当 HTML 重新解析,<script>alert(1)</script> 会被执行。
安全做法不是手写正则替换,而是复用浏览器原生逻辑:
立即学习“前端免费学习笔记(深入)”;
Python 里用 html.escape() 还是自己写正则?
Python 3.4+ 自带 html.escape(),它默认只转义那 5 个核心字符(<、>、&、"、'),且可选 quote=True/False 控制是否转义引号——这是最稳妥的选择。
自己写正则容易翻车:
示例:html.escape("10 → <code>10 < 20 & user said 'hi'
模板引擎自动转义 ≠ 你就可以躺平
Jinja2、Django 模板默认开启 autoescape,但漏洞常出现在「绕过点」:
真正安全的边界不在模板层,而在数据流入点:API 响应、数据库读取、文件导入,这些地方就要决定“这个字符串最终在哪渲染”,并提前按目标上下文做对应编码。



















