HTML注入本质是未转义的用户输入被当作代码执行,关键在于用户可控数据(如URL参数、API返回字段)直接拼入HTML且未转义,常见于innerHTML赋值、模板字符串拼接、服务端模板漏转义等场景。

HTML注入本质是未转义的用户输入被当代码执行
关键判断:只要把用户可控的数据(比如 URL 参数、表单提交内容、API 返回字段)直接拼进 HTML 文本里,又没做转义,就存在风险。常见错误是用 innerHTML 赋值、模板字符串拼接、document.write,或服务端模板(如 EJS、Jinja)里漏掉转义标记。
典型错误现象:<script>alert(1)</script> 这种输入一提交,页面就弹窗;或者用户发帖时插入 <img src="x" onerror="fetch('/api/token')" alt="HTML注入风险怎么防_XSS攻击防范建议【说明】" >,静默窃取凭证。
- 服务端输出时,优先用带自动转义的模板引擎(如 Nunjucks 的
{{ value }},而非{% raw %}{{ value }}{% endraw %}) - 前端动态渲染时,避免
innerHTML,改用textContent或createElement+appendChild - 必须用
innerHTML的场景(如富文本),只允许白名单标签(p,strong,ul等),并用 DOMPurify 等库清理
哪些地方最容易漏掉转义
不是所有“插入”都危险,但以下位置几乎 100% 需要检查:
-
location.search解析后的参数直接写入页面(比如搜索关键词高亮) - 接口返回的
data.title、data.content直接插进div.innerHTML - 使用
eval、setTimeout字符串参数、new Function拼接用户输入 - Vue/React 中误用
v-html或dangerouslySetInnerHTML,且未过滤
特别注意:JSON 数据本身安全,但一旦用 JSON.parse() 后再拼进 HTML,就脱离了安全上下文——转义必须在插入前完成,不能靠“数据来源干净”假设。
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
立即学习“前端免费学习笔记(深入)”;
Content-Security-Policy 是兜底,不是替代方案
CSP 能大幅降低 XSS 成功后的危害(比如禁止内联脚本、限制 script-src 只到自己域名),但它不修复漏洞本身。攻击者仍可能通过 fetch 泄露数据、触发 CSRF、或利用 img 标签打点。
- 推荐基础策略:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; - 绝对不要用
'unsafe-inline'或'unsafe-eval',除非你明确知道为什么且已评估过风险 - 开发时用
Content-Security-Policy-Report-Only先收集违规,再上线正式策略
策略再严,也防不住把 javascript:alert(1) 写进 href 属性这种低级错误——CSP 只是最后一道闸,不是免检通行证。
JSON 和属性值里的注入常被忽略
很多人以为只防 <script></script> 就够了,但攻击还能藏在属性里。比如:<a href="javascript:fetch('/me')"></a>、<img src="x" onerror="alert(1)" alt="HTML注入风险怎么防_XSS攻击防范建议【说明】" >,甚至 <div data-id="1" onclick="alert(1)"> 这种闭合引号的写法。
<ul>
<li>往 HTML 属性赋值时(如 <code>el.setAttribute('title', userInput)),必须对双引号、单引号、反斜杠、、<code>> 做转义
<script>const data = <%= JSON.stringify(userInput) %></script>),必须用 JSON.stringify 并确保外层引号匹配,否则会提前闭合he.escape,浏览器可用 DOMPurify.sanitize 或 encodeURIComponent(仅限 URL 参数)最隐蔽的风险点:属性值和事件处理器是两个不同解析上下文,同一段输入在 title 里安全,在 onclick 里就可能执行——别指望一次转义通吃所有位置。


















