innerHTML赋值前必须转义,否则直接写element.innerHTML=userInput是前端XSS最常见入口,哪怕用户只输入一个恶意脚本也会触发攻击。

innerHTML 赋值前必须转义,否则等于开后门
直接写 element.innerHTML = userInput 是前端 XSS 最常见的入口。哪怕用户只输入一个 或 <code>",都可能被浏览器解析为标签或属性闭合点,进而触发 <img src=x onerror=alert(1)> 这类 payload。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 纯文本场景一律改用
element.textContent = userInput——不解析 HTML,零风险 - 必须渲染富文本时,先过
DOMPurify.sanitize(dirtyHtml),再赋给innerHTML;别自己写正则删<script> - 服务端返回的 JSON 字段若已含 HTML 实体(如
"<div>"),前端不能再二次转义,否则显示为字面量<h3>HTML 属性值里插用户数据,光转义 < > 不够</h3> <p>把用户输入塞进 <code>title="{{ userInput }}"或data-id="{{ userInput }}"时,攻击者能用引号提前闭合属性,再注入事件处理器,比如输入" onclick="alert(1),最终生成title="" onclick="alert(1)"。实操建议:
立即学习“前端免费学习笔记(深入)”;
- 双引号包裹的属性(
title="xxx")必须转义"→";单引号包裹(title='xxx')则转义'→' - URL 类属性(
href、src)不能只做 HTML 转义,得先encodeURIComponent(),再拼入带引号的属性值 - 绝对避免
<button onclick="doSomething('{{ userInput }}')">这种写法——事件处理器内嵌用户数据,无解
JS 字符串上下文需要 JS 转义,不是 HTML 转义
在
<script>var name = "${userInput}";</script>中,只对、<code>&做 HTML 实体转义完全无效。攻击者可输入\u003cimg\u0020onerror=alert(1)\u003e,JS 引擎照样执行。
anything-to-html下载将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 优先用
JSON.stringify()包裹用户数据:var name = ; - 若必须拼接字符串,确保使用 JS 字符串安全转义函数(如 Node.js 的
jsesc库),而非 HTML 转义函数 - 禁止用
eval()、new Function()、setTimeout(string)执行任何含用户输入的 JS 片段
自己写 escapeHTML 函数极易绕过
网上常见这种代码:
str.replace(/&/g, '&').replace(/, '。它漏掉 Unicode 变体、注释干扰、大小写混淆等大量绕过方式,比如 <code><img alt="HTML中防范XSS跨站脚本攻击的前端编码转义策略" >或<scr>ipt>alert(1)</scr>都能逃逸。实操建议:
立即学习“前端免费学习笔记(深入)”;
- 前端不要自己实现转义逻辑;用
DOMPurify.sanitize()处理 HTML,用JSON.stringify()处理 JS 上下文 - 服务端转义必须用语言原生函数:PHP 用
htmlspecialchars($str, ENT_QUOTES, 'UTF-8'),Java JSTL 用<c:out value="${userInput}" /> - 模板引擎中确认是否默认转义:Jinja2 默认转,但
{{ userInput | safe }}会绕过;EJS 默认不转,必须手动
关键点在于:XSS 防护不是“加一层过滤”,而是按输出位置选择对应编码规则。同一个用户输入,在 HTML 文本、属性、JS 字符串、URL 四种上下文里,要分别走四套转义逻辑。漏掉任意一种,就等于留了一扇没锁的门。
- 双引号包裹的属性(


















