
本文详解为何 中的恶意脚本不会执行,但通过字符串拼接插入 HTML 会触发 XSS,并提供使用 document.createTextNode()、jQuery 的 text() 方法等专业级防护方案。
本文详解为何 `` 中的恶意脚本不会执行,但通过字符串拼接插入 html 会触发 xss,并提供使用 `document.createtextnode()`、jquery 的 `text()` 方法等专业级防护方案。
在 Web 开发中,将用户可控数据动态插入 DOM 是常见需求,但若处理不当,极易引发跨站脚本(XSS)漏洞。以如下场景为例:
<input id="bc_hare_status_inp" value="<script>alert('hi')</script>">
该 <input> 的 value 属性虽包含 <script></script> 字符串,但浏览器仅将其视为纯文本值,不会解析或执行其中的脚本——这是 HTML 规范对表单控件的内置保护机制。
然而,真正的风险出现在后续 DOM 操作中:
-
✅ Case 1(看似安全,实则仍需防御):
const hareStatus = $("#bc_hare_status_inp").val(); const rp_html = `<input type="text" value="${hareStatus}" style="width:250px">`; $('select[name="hare_status"]').replaceWith(rp_html);此处
hareStatus被插入到新<input>的value属性中。虽然当前上下文(属性值)本身不执行脚本,但若未来该值被错误地用于innerHTML、$.html()或其他可执行上下文(如eval()、setTimeout(string)),攻击面即被打开。CodeQL 标记为“Dom text reinterpreted as HTML”正是出于纵深防御原则:任何未经转义的用户数据进入 HTML 构建流程,都构成潜在风险。 -
❌ Case 2(明确高危):
const rp_html = `${hareStatus}`; // 直接拼接为 HTML 片段 $('select[name="hare_status"]').replaceWith(rp_html); // → 执行 alert('hi')此时恶意字符串被直接写入 DOM,浏览器将其解析为 HTML 节点,
<script></script>立即执行,XSS 成功。
✅ 推荐防护方案
方案一:使用 document.createTextNode()(原生、零依赖)
const hareStatus = $("#bc_hare_status_inp").val();
const textNode = document.createTextNode(hareStatus);
$('select[name="hare_status"]').replaceWith(textNode);
createTextNode() 保证内容以纯文本节点插入,完全绕过 HTML 解析器,绝对安全。
方案二:使用 jQuery .text() 方法(语义清晰、自动转义)
const hareStatus = $("#bc_hare_status_inp").val();
$('<input type="text" style="width:250px">').val(hareStatus)
.insertAfter('select[name="hare_status"]')
.prev('select[name="hare_status"]').remove();
// 或更简洁地:
$('select[name="hare_status"]').replaceWith(
$('<input type="text" style="width:250px">').val(hareStatus)
);
注意:.val() 设置的是表单控件的值(安全),而 .html() / .append() 才会触发 HTML 解析。
方案三:服务端预转义 + 前端严格校验(纵深防御)
- 数据入库前对
, <code>>,",',/等字符进行 HTML 实体编码(如→ <code>); - 前端读取后,优先使用
.text()或textContent而非.html(); - 对必须渲染 HTML 的场景(如富文本),使用
DOMPurify.sanitize()进行白名单过滤。
⚠️ 关键注意事项
- 不要依赖“当前上下文看起来安全”来跳过转义——DOM 插入路径可能随业务演进变化;
- 避免使用
innerHTML、$.html()、模板字符串直插未过滤变量(如`${userInput}`); -
input.value = ...是安全的,但element.innerHTML = ...是危险的,二者不可混淆; - 使用现代框架(React/Vue)时,其默认的 JSX/模板插值已自动转义,但仍需警惕
dangerouslySetInnerHTML等逃逸 API。
安全无小事。一次未转义的字符串拼接,可能让整个应用暴露在 XSS 攻击之下。坚持“所有用户输入皆不可信”,并在每一层 DOM 操作前做显式净化,才是构建健壮前端应用的基石。










