最直接有效的防护是服务端对用户输入做html实体编码,因其将、&、"、'五个关键字符转为不可解析的实体形态,从根源切断html标签语法有效性,且必须按上下文选用对应编码方式。

最直接有效的防护是服务端对用户输入做 HTML 实体编码,而不是依赖前端过滤、正则清洗或“看起来安全”的黑名单。
为什么 htmlspecialchars 或 html.escape 是第一道硬防线
浏览器看到 <script></script> 就会执行,但看到 <script> 就只当它是普通文本。实体编码把 、<code>>、&、"、' 这五个关键字符转成不可解析的形态,从根源上切断 HTML 标签的语法有效性。
- PHP 必须用
htmlspecialchars($input, ENT_QUOTES, 'UTF-8')—— 缺少ENT_QUOTES会导致单引号漏转,onerror='...'类攻击仍可生效 - Python 推荐
html.escape(input, quote=True),quote=True才能转义属性中的双引号和单引号 - Node.js 用
he.escape(input),别用escape-string-regexp这类通用字符串工具,它不处理 HTML 上下文语义 - Java 中
StringEscapeUtils.escapeHtml4()是可靠选择;URLEncoder.encode()是 URL 编码,完全不适用
富文本场景下白名单过滤不能省,但必须后端执行
如果业务真要保留 <b></b>、<img> 等标签(比如后台编辑器输出),仅靠前端 DOMPurify.sanitize() 是危险的:攻击者可绕过 JS 直接发请求。净化必须落在服务端。
- Python 用
bleach.clean(input, tags=['p', 'br', 'strong', 'em'], attributes={'img': ['src', 'alt']}, strip=True)——strip=True会删掉未授权标签及其内容,比strip=False(只留文本)更安全 - Java 用 Jsoup:
Jsoup.clean(input, Whitespace.relaxed().addTags("p", "br", "strong")),注意relaxed()默认允许href,需额外调用addProtocols("a", "href", "http", "https", "/")防javascript:协议 - Node.js 用
sanitize-html时,务必配置allowedSchemes: ['http', 'https', '/'],否则<a href="data:text/html;base64,..."></a>可能逃逸
CSP 不是替代方案,而是最后一层兜底
CSP 头无法阻止恶意 HTML 被插入 DOM,它只管“插入之后能不能执行”。如果服务端没做实体编码或白名单,CSP 就像给开着门的房子装防盗窗。
- 至少设置
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self' - 禁用内联脚本:
script-src 'self'后绝不能带'unsafe-inline',哪怕只有一处<script>alert(1)</script>就全盘失效 - 若必须支持内联脚本(极少数场景),用 nonce:生成随机值写入响应头
script-src 'nonce-abc123',再在对应<script nonce="abc123"></script>标签里使用 —— 每次请求 nonce 必须唯一且不可预测
前端渲染时避免踩 innerHTML 和 dangerouslySetInnerHTML 的坑
即使后端做了净化,前端错误使用 DOM API 仍会重新引入风险。框架默认防护不是万能的。
- 永远优先用
textContent渲染纯文本字段(昵称、标题、评论摘要) - React 中禁用
dangerouslySetInnerHTML,除非你 100% 确认该数据已由后端白名单过滤并返回为可信 HTML - Vue 的
v-html同理,不要绑定 raw user input;若必须用,确保数据来源是后端bleach.clean()处理后的结果 - 警惕
insertAdjacentHTML、document.write、eval()、setTimeout(string)—— 它们都不受框架保护
真正容易被忽略的点是:**上下文决定编码方式**。同一个用户输入,放进 HTML 文本节点、放进 href 属性、放进 onclick 事件、放进 URL 查询参数,需要的编码函数完全不同。没有“一招鲜”,只有按上下文选对 html.escape、encodeURIComponent、JSON.stringify 或 CSP 限制。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











