什么是 XSS 攻击?如何防范?
2025年12月24日
XSS (cross-site scripting) 是很常见的网路攻击。身为网页前端或后端工程师,在面试中,很常会问到 XSS 的问题,因为面试官要确定你对于 XSS 的基本概念需要有所掌握。
什么是 XSS?
所谓的 XSS (cross-site scripting) 攻击,指当某个攻击者成功让恶意脚本程式代码被注入到「网站输出的内容」中,导致该程式代码在其他使用者的浏览器上、以该网站的身份被执行,就好像这段脚本原本就属于该网站一样。
对浏览器而言,因为这段程式代码看起来是从该网站发出的,浏览器会给予完整的权限去存取该网站的所有资源 (包括 Cookie、Session Token 等敏感资讯),进而造成严重的问题。
如果想了解可以输入什么样的恶意 Javascript 语法,让系统出现问题,可以透过这个 网站 来试试看。
因为 JavaScript 几乎可以做到任何事,所以 XSS 的攻击能做到的事情也是五花八门。举例来说,窃取别的用户的 cookie,然后透过拿到的 cookie 来发送请求;或者是窜改网页内容。下面分享一个早些年直播平台 Twitch 因为防御做得不够完善,被恶搞的例子,就是透过 XSS 达成的。
近年来著名的 XSS 攻击案例之一,是《how to hack discord, vercel and more with one easy trick》一文所揭露的。
这个漏洞之所以会被发现,是因为前阵子 Discord 宣布把开发者文件,由自建的平台,改成用 Mintlify 来托管;由于这几位白帽骇客平常就是用 Discord 来交流,所以这个迁移让他们起了对 Mintlify 平台的兴趣。
在探索一番后,他们发现 Mintlify 在所有文件网站底下,都暴露了一个 /mintlify/static/[subdomain]/... 的路径,用来读取文件库裡的静态资产,例如图片、SVG 等等。
在看到这个路径时,他们思考到「不知该端点会不会确认所在的网域?」,结果试了一下发现还真的没有确认。这代表假如自己办一个 Mintlify 的帐号,然后上传 SVG 档案到自己的 Mintlify 帐号,然后透过 Discord 的网域来存取该 SVG 档案。
该白帽骇客实际尝试,上传了一张带有恶意脚本的 xss.svg 到自己的 evascoolcompany 帐号,然后再到 https://discord.com/mintlify/static/evascoolcompany/xss.svg 网址中,结果该恶意 JavaScript 脚本真的被执行了。
这种漏洞又被称为单次点击 XSS 攻击 (one-click XSS),攻击者只需要诱使受害者点击一个看似正常的连结,就能在受害者的浏览器中执行任意程式代码。
举例来说,你以为你点了一个看起来像 Discord 官方文件的连结,但实际上浏览器就会在 discord.com 这个网域下执行攻击者的程式代码,让 localStorage、token、登入状态,全部都能被窃取。
XSS 攻击的类型
Stored XSS
被保存在资料库中的 Javascript 引起的攻击称为 Stored XSS,最常见的就是文章、留言等,因为用户可以任意输入内容,若没有检查,则<script> 等标签就会被视为正常的 HTML 做执行。
Reflected XSS
此类型不会被存在资料库中,主要透过用户发出恶意的请求,倘若后端没有过滤而直接将结果回传前端的话,就有可能执行到恶意的代码,举例来说:

倘若用户填完名字后,显示的代码如下:
<h3> Hi, <?=$_GET['name'] ?> </h3>
则很有可能被用户恶意填写为:
https://websiteA/welcome?name=<script>alert(123)</script>
此种手法通常都用于钓鱼、社交工程等方式诱骗用户点入连结。
DOM-Based XSS
DOM 全名为 Document Object Model,它可以利用 Javascript 动态产生完整的网页,不用透过后端,因此 DOM-Based XSS 是指网页上的 Javascript 在执行过程中,没有检查输入资料,使得操作 DOM 的过程中带入了恶意代码。

在同一个网址上,透过 DOM 的方式直接显示在前端页面
<script>
var hello = function () {
let name = document.getElementById("name").value;
document.getElementById("show").innerHTML = name;
};
</script>
<h3>Hi, <span id="show"></span></h3>
<input id="name" type="text" />
<button onclick="hello();">Go</button>
因此只要将输入的内容写为
<img src="#" onerror="alert(123);" />
则会因为读取不出图片而产生错误,触发 onerror ,并执行 alert(123) 。
此类型的攻击,或许没办法直接让用户输入语法,但可以搭配 Stored XSS 和 Reflected XSS 制造出内容,再藉由 Javascript 动态产生有效的 DOM 物件来执行恶意代码。
如何防御 XSS?
DOM-Based 防范 - 检查输入栏位。此攻击需要从前端去防范,任何的输入栏位,例如留言栏位、档案上传栏位、表单的栏位等,都要有跳脱的机制,让脚本被转换成字符串。举例来说,如果攻击者输入
<script>alert(1)</script>,我们把<转成<,在画面上依然是呈现<但是对程式来说,它不会被当成 HTML 标签来解析。确保来自使用者的脚本不会被执行。透过CSP (content security policy) 来设定有哪些网域(domains ) 来的脚本该被浏览器认为是该被执行的,然后浏览器只执行那些该被执行的脚本。举例来说,如果设定只有来自与网站同一个网域的脚本可被执行,那么其他由恶意攻击者注入的脚本,就会被认定成不该执行的,就不会被执行。
Stored、Reflected 防范。这两种都必须由后端进行防范,任何允许用户输入的内容都要检查,删除相关的关键字,像是
<script>、onerror等指令。