htmlspecialchars() 必须显式传 ENT_QUOTES 和 'UTF-8',否则单引号不转义、编码误判导致 XSS;多上下文使用需分别转义,如 HTML 文本用 htmlspecialchars()、URL 用 encodeURIComponent()、JS 字符串用 JSON.stringify()。

htmlspecialchars() 必须显式传 ENT_QUOTES 和 'UTF-8'
不加参数或只传第一个参数的 htmlspecialchars($input) 在 PHP 中默认不转义单引号,且编码检测可能 fallback 到 ISO-8859-1,导致 UTF-8 多字节字符被截断或解析异常——这两点都直接构成 XSS 绕过条件。
- 攻击者输入
user' onmouseover=alert(1),若未用ENT_QUOTES,单引号原样保留,塞进data-name='{{ user }}'就会提前闭合属性并注入事件 - 用户昵称含中文或 emoji(如 ?),若没指定
'UTF-8',htmlspecialchars()可能误判字节边界,输出乱码甚至截断,后续 JS 解析时可能触发 DOM 操作异常 - 绝对不要用
ENT_HTML401:它兼容旧标准,但不处理 Unicode 引号变体(如 `‘`),而现代浏览器仍会解析执行
属性值里插用户数据,光转 HTML 实体远远不够
把用户输入拼进 title="{{ user }}" 或 href="?q={{ user }}" 时,htmlspecialchars() 只解决 HTML 文本上下文,对属性闭合、URL 协议、JS 执行完全无效。
- 双引号属性(
title="...")必须同时转义"→",否则user" onclick="alert(1)直接变成title="user" onclick="alert(1)" - URL 参数必须走
encodeURIComponent(),不是htmlspecialchars():后者不编码/、?、=,拼进location.href = '/search?q=' + userInput会导致路径跳转或 query 注入 - 禁止写
<button onclick="doSomething('{{ user }}')"></button>:这是 JS 字符串上下文,需先JSON.stringify(user)再嵌入,否则引号、换行、反斜杠全都会破坏语法
innerHTML 赋值前不做转义 = 主动执行 XSS
前端 JS 动态渲染用户内容时,element.innerHTML = userInput 是最危险的常见操作——浏览器会立刻解析并执行其中任意脚本、事件或 iframe。
- 纯文本展示一律用
element.textContent = userInput,零风险,不解析任何标签 - 真要渲染富文本(如评论带链接),必须先调
DOMPurify.sanitize(dirtyHtml),它基于真实 HTML 解析器重建 DOM,能剥离onerror、javascript:、data:text/html等全部已知绕过模式 - 绝对不要自己写正则删
<script></script>或过滤on*:绕过方式太多,比如<img src="https://img.php.cn/" alt="防御性编程在HTML文档结构生成及标签转义中的深度应用">或<scr>ipt></scr>都能逃逸
同一段用户数据用在多个上下文,必须分别转义
用户昵称可能同时出现在 HTML body、data-uid 属性、JS 变量、URL query 四个地方。只做一次 htmlspecialchars() 或只做一次 encodeURIComponent(),必然在某个位置失效。
立即学习“前端免费学习笔记(深入)”;
- HTML 文本内容:
he.escape()(JS)或htmlspecialchars()(PHP) - 插入
<script></script>内部:JSON.stringify(user)包裹后直接写入,别再套引号 - 作为 URL query 参数:
encodeURIComponent(user),注意不是encodeURI()(它不编码/、?) - CSS 值或 style 属性:避免动态拼接;改用 CSS 自定义属性 + JS 控制,例如
element.style.setProperty('--user-color', userColor)



















