跳转至

XSS原理

一、什么是 XSS 漏洞

XSS(Cross-Site Scripting,跨站脚本)是一种发生在**客户端浏览器层面的安全漏洞**。它的本质是:

网站没有正确处理用户输入,导致攻击者的恶意 JavaScript 被嵌入到网页中,并在其他用户的浏览器里执行。

需要注意两点:

  1. XSS 攻击的代码最终是在**受害者的浏览器里运行**,而不是在服务器上运行。
  2. 漏洞通常源自**服务器对用户输入处理不当,或前端代码使用不安全方式渲染数据**。

从危害上看,成功利用 XSS 后,攻击者通常可以:

  • 读取用户的 Cookie,从而劫持登录状态
  • 伪造用户操作,比如帮用户自动点赞、发帖、转账等
  • 篡改页面内容,插入钓鱼界面
  • 监听用户输入,窃取密码
  • 在页面中植入恶意脚本,进一步传播攻击

二、XSS 漏洞的根本原理

理解 XSS 的关键在于:网页既包含数据,也包含可执行代码

浏览器的工作方式是:

  • 遇到普通文本,就直接显示
  • 遇到 <script> 之类的标签,就当作代码执行

如果网站**直接把用户输入嵌入到 HTML 中,而没有进行安全处理**,问题就出现了。

举个最简单的例子:

正常情况下,用户输入评论:

这个网站很好

服务器返回的 HTML 可能是:

<p>这个网站很好</p>

浏览器正常显示。

但如果攻击者输入:

<script>alert('被攻击')</script>

而服务器原样输出:

<p><script>alert('被攻击')</script></p>

浏览器看到 <script> 就会执行,这时 XSS 就发生了。

可以用一句话概括原理:

用户可控输入 + 不安全输出 + 浏览器执行 = XSS


三、XSS 的三种主要类型

目前业界通常将 XSS 分为三类:

  1. 反射型 XSS
  2. 存储型 XSS
  3. DOM 型 XSS

下面逐一说明。


1. 反射型 XSS

反射型 XSS 的特点是:一次性触发,不会长期存储在服务器。

典型流程是:

  1. 攻击者构造一个带恶意代码的链接
  2. 诱导受害者点击
  3. 服务器接收到参数后,未经过滤直接返回给浏览器
  4. 浏览器解析页面并执行恶意脚本

之所以叫“反射型”,是因为服务器只是把用户输入“反射回来”,本身并没有保存它。

常见场景包括:

  • 搜索结果页
  • 错误提示页
  • 参数回显页面

例如:

https://site.com/search?q=<script>...</script>

如果服务器直接把 q 的内容展示出来,就可能触发反射型 XSS。


2. 存储型 XSS

存储型 XSS 是**危害最大的一种类型**,因为恶意代码会被长期保存在服务器上。

典型流程是:

  1. 攻击者在评论区、论坛、个人资料页提交恶意代码
  2. 服务器把内容存入数据库
  3. 其他用户访问页面时,服务器把含有恶意代码的内容取出并展示
  4. 所有访问该页面的用户都会中招

典型场景包括:

  • 论坛评论
  • 博客留言
  • 社交媒体帖子
  • 在线协作文档
  • 用户个人资料

危险之处在于:

  • 一次攻击,可能影响成千上万用户
  • 不需要诱导点击,只要访问页面就会触发
  • 攻击可以长期存在

3. DOM 型 XSS

DOM 型 XSS 与前两种不同,它的关键点是:漏洞主要出在前端 JavaScript 代码,而不是服务器。

在这种情况下,服务器可能是安全的,但前端代码处理数据的方式不安全。

例如:

document.getElementById("msg").innerHTML = location.hash;

如果用户访问:

https://site.com/#<script>alert(1)</script>

浏览器会把 hash 里的内容插入页面并执行,而服务器根本没有参与处理。

这种类型在现代单页应用(SPA)中比较常见,比如使用 Vue、React、原生 JavaScript 的前端页面。


四、三种 XSS 的对比

从性质上看:

  • 反射型:临时、一次性,需要诱导点击
  • 存储型:长期存在、自动触发,危害最大
  • DOM 型:主要由前端代码问题导致

从责任方看:

  • 反射型和存储型主要是服务器处理不当
  • DOM 型主要是前端开发方式不安全

五、从原理理解为什么会发生 XSS

XSS 之所以频繁出现,主要有三个原因:

第一,开发者习惯直接拼接 HTML,例如:

element.innerHTML = userInput;

第二,服务器对用户输入没有做充分的转义或过滤。

第三,浏览器本身的机制是“看到脚本就执行”,只要页面里出现恶意脚本,它就会运行。


六、简单的防御思路

理解原理后,防御逻辑也会变得清晰:

  1. 不要把用户输入直接当作 HTML 解析。
  2. 在输出到页面前,对特殊字符进行转义,比如把 < 变成 <
  3. 尽量使用安全的前端 API,例如 textContent 而不是 innerHTML
  4. 对重要网站开启 Content-Security-Policy(CSP),限制脚本来源。