通过 innerHTML 引发 XSS 及其预防方法
了解跨站脚本攻击,以及相较于 innerHTML 更安全的替代方案
通过 innerHTML 引发 XSS 及其预防方法 是 CoddyKit 上的免费 HTML Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 HTML Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 HTML Academy 课程共包含 4 节课。
核心漏洞
设置 el.innerHTML = userInput 会将字符串解析为 HTML。如果 userInput 包含 <script> 标签或事件处理程序属性(onclick、onerror),浏览器就会解释它们,从而在页面上执行攻击者控制的代码。
为什么这种问题很常见
任何将用户数据插入 HTML 的代码——无论是服务器模板还是客户端渲染——只要没有对数据进行转义,就存在 XSS 风险。当 API 响应包含用户内容时,从 API 响应构建 innerHTML 的单页应用尤其容易受到攻击。
具体示例
通过 div.innerHTML = `Welcome, ${user}` 设置用户名 "Bob<img src=x onerror=alert(1)>" 时,图像加载失败会执行 alert(1)。同样的内容如果作为纯文本通过 textContent 设置,则不会造成危害——浏览器看到的只是字符,而不是标签。
// VULNERABLE
div.innerHTML = `Hi, ${user.name}`;
// SAFE
div.textContent = `Hi, ${user.name}`;使用 textContent 处理纯文本
textContent 只设置文本——HTML 特殊字符会以字面字符显示,绝不会被当作标签。这在 90% 的情况下都是正确的工具。只有在确实需要渲染标记而不是文本时,才切换到 innerHTML。
使用 DOM 方法构建结构
要使用用户数据创建元素,请通过 createElement 和 textContent 构建:const li = document.createElement("li"); li.textContent = name; ul.appendChild(li);。结果在结构上与 innerHTML 完全相同,但从构建方式上就能确保 XSS 安全。
必须使用 innerHTML 时
对于服务器生成的可信 HTML(您自己的模板输出,或来自可信编辑器且已清理的富文本),使用 innerHTML 没有问题。对于来自不可信来源的数据,未经清理绝不能直接使用它。
使用 DOMPurify 清理富文本
如果用户提交富文本(例如评论编辑器内容或 Markdown 渲染结果),请在设置 innerHTML 前进行清理:el.innerHTML = DOMPurify.sanitize(richHtml)。DOMPurify 会移除危险的标签和属性,同时保留 <b>、<em>、<a> 等安全格式。
insertAdjacentHTML 具有相同风险
el.insertAdjacentHTML("beforeend", html) 会解析 HTML 字符串,因此与 innerHTML 面临相同的 XSS 攻击面。规则也相同:绝不要直接传入用户数据;请进行清理或使用 DOM 方法。document.write 也是如此,不过现在不应该再使用它了。
框架默认行为
React、Vue、Svelte 和 Angular 默认都会转义插值文本——{name} 是安全的。它们提供了绕过机制(React 中的 dangerouslySetInnerHTML、Vue 中的 v-html),但同样存在 XSS 风险;请谨慎使用,并配合清理。
属性注入
即使属性值也可能成为攻击途径:<a href={url}> 中的 url="javascript:alert(1)" 会在点击时执行。请逐个协议验证 URL,在将用户输入放入 href、src 或其他承载 URL 的属性之前,只允许使用 http:、https:、mailto: 和 tel:。
Trusted Types 策略
现代浏览器支持 Trusted Types:使用 require-trusted-types-for 'script' 配置 CSP 后,innerHTML 会拒绝原始字符串,只有经过策略封装的值才能通过。这通过 API 机制而不是依靠开发规范来防止 XSS。
纵深防御
单个防护层都不够。请结合使用:在服务器上验证输入,在渲染时转义输出,使用 CSP 阻止注入脚本,使用可信类型拒绝原始字符串,并对任何 innerHTML 的使用进行安全审查。分层防御即使其中一层存在错误也能继续发挥作用。
知识检查
为什么 el.textContent = userInput 可以安全地防范 XSS,而 el.innerHTML = userInput 却很危险?
总结
对用户输入使用 innerHTML 是经典的 XSS 攻击途径。对于文本,请使用 textContent;对于结构,请使用 createElement+textContent;需要富 HTML 时,请使用 DOMPurify。对于属性值,请验证 URL 方案。通过叠加 CSP 和可信类型,来化解那些漏过代码审查的错误。现代框架默认会进行转义——请尽量少用它们不安全的绕过机制,并对其进行审查。
用 AI 导师学习 HTML — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 40
- 课程
- 159
常见问题解答
「通过 innerHTML 引发 XSS 及其预防方法」课时是免费的吗?
是的 — 「通过 innerHTML 引发 XSS 及其预防方法」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 HTML Academy 课程的其余内容,请升级到 CoddyKit PRO。 HTML Academy 课程共包含 4 节课。
「通过 innerHTML 引发 XSS 及其预防方法」这节课中我会学到什么?
了解跨站脚本攻击,以及相较于 innerHTML 更安全的替代方案 你通过在浏览器中直接运行的动手代码来练习 HTML Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 HTML Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 HTML Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「通过 innerHTML 引发 XSS 及其预防方法」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 HTML Academy 课中编写并运行代码吗?
能。每节 HTML Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 内容安全策略:meta http-equiv
- 通过 innerHTML 引发 XSS 及其预防方法
- iframe 沙箱与权限策略
- HTTPS 与子资源完整性