最安全的做法是纯文本场景一律用 textcontent,富文本场景必须用 dompurify 等 sanitizer 净化 html;动态拼接时需对每个用户输入值单独 html 转义;事件绑定应避免内联脚本,改用事件委托。

纯文本场景:一律走 textContent
用户名、错误提示、API 返回的描述字段、搜索关键词高亮前的原始词……这些都不含标签,也不该被解析。
别写:el.innerHTML = userInput
改写:el.textContent = userInput
浏览器完全跳过 HTML 解析流程,连 `` 都当普通字符显示,天然免疫 XSS。
富文本场景:必须用 sanitizer 净化
如果后端返回的是 `
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
欢迎你!
` 这类结构,且业务允许保留部分格式,就不能靠手动删 `<script>` 或正则过滤——绕过方式太多。<br> 推荐用 <strong>DOMPurify(主流、持续维护、支持白名单):<br> <ul> <li>只放行你需要的标签,比如 <code>['p', 'b', 'i', 'a', 'br'] <li>只保留安全属性,比如 <code>['href', 'target', 'class'] <li>自动剔除 <code>onerror、<code>onclick、<code>javascript: 等危险模式 示例:<br> <pre class="brush:php;toolbar:false;">const clean = DOMPurify.sanitize(dirtyHtml, { ALLOWED_TAGS: ['p','b'], ALLOWED_ATTR: ['class'] });<br> el.innerHTML = clean; <h3>动态拼接 HTML 字符串:先转义再组装 <p>用模板字符串或 <code>map().join() 批量生成列表时,若中间混入用户数据(如标题、ID),必须对每个变量单独做 HTML 实体编码。<br> 关键不是“整个字符串扫一遍”,而是“每个不可信值进字符串前就转义”。<br> 一个轻量可靠的转义函数:<br> <pre class="brush:php;toolbar:false;">function escapeHtml(str) {<br> return String(str)<br> .replace(/&/g, '&')<br> .replace(/, '<')<br> .replace(/>/g, '>')<br> .replace(/"/g, '"')<br> .replace(/'/g, "'");<br> }<br> 然后这样用:<br> <code>data.map(item => `<div>${escapeHtml(item.title)}`).join(''); <h3>事件绑定别写内联脚本,改用事件委托 <p>通过 `innerHTML` 插入的按钮、链接,在插入瞬间并不存在,没法提前绑事件。<br> 更糟的是,有人会写:<code><button onclick="del(${id})">删——引号嵌套一错,JS 就崩;更严重的是,`id` 若含 `'` 或 `"`,可能拼出可执行代码。<br> 正确做法:<br> <ul> <li>HTML 里只放干净结构:<code><button data-id="${item.id}">删 <li>在父容器上监听点击:<code>parentEl.addEventListener('click', e => { if (e.target.matches('button[data-id]')) { del(e.target.dataset.id); } }); </script>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










