免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

XSS攻击实战:从靶场通关到防御策略全解析

XSS攻击实战:从靶场通关到防御策略全解析 1. 项目概述从靶场实战深入理解XSS攻击如果你正在学习Web安全或者对渗透测试感兴趣那么“XSS攻击”这个词你一定不陌生。它常年盘踞在OWASP Top 10榜单上是Web应用最常见、也最容易被开发者忽视的漏洞之一。但光看理论总觉得隔靴搔痒不知道攻击到底是怎么发生的防御又该从何下手。这就是为什么我们需要一个像Xss-Labs这样的靶场。它不是一个复杂的综合靶场而是专门针对XSS漏洞设计的闯关游戏从最简单的反射型XSS到需要绕过多重过滤的复杂场景一共设计了20关本文聚焦1-10关让你在亲手“攻击”的过程中把XSS的原理、分类、利用方式和绕过技巧吃得透透的。我花了几天时间把Xss-Labs的前10关从头到尾打了一遍过程中踩了不少坑也总结出一些绕过过滤的“骚操作”。这篇通关教程我会带你一关一关地过但不止步于给出答案。我会详细拆解每一关的代码逻辑告诉你为什么常规的payload不行过滤规则是怎么设计的我们又该如何“见招拆招”。无论你是刚入门的安全新手想通过实战建立直观认知还是有一定基础的开发者希望深入理解XSS的防御盲点这篇基于Xss-Labs靶场的实战剖析都能给你带来实实在在的收获。记住最好的防御源于对攻击的深刻理解。2. 环境准备与靶场搭建2.1 靶场选择与部署Xss-Labs是一个开源且专注于XSS漏洞训练的靶场项目。相比于DVWA、Pikachu等综合靶场它的优势在于目标纯粹、梯度设计合理非常适合用于专项突破。你可以从GitHub等代码托管平台找到它的源码。部署方式极其简单因为它本质上就是一个PHP项目。通常你只需要一个集成的Web服务器环境比如PHPStudy、XAMPP或WAMP。将下载的Xss-Labs源码包解压放到服务器的网站根目录例如www或htdocs下。然后启动Apache和MySQL服务虽然Xss-Labs不一定需要数据库但启动以备不时之需。最后在浏览器访问http://localhost/xss-labs/具体路径根据你的放置位置调整看到闯关列表页面就说明部署成功了。注意强烈建议在虚拟机或隔离的本地环境中搭建和练习。尽管是靶场但其中涉及的攻击代码是真实的避免因误操作影响其他网络环境。2.2 必备工具与浏览器设置工欲善其事必先利其器。打靶场有合适的工具能事半功倍。浏览器与开发者工具现代浏览器Chrome、Firefox、Edge自带的开发者工具是核心武器。主要用到两个面板元素Elements查看网页HTML结构分析我们的输入被插入到了哪个标签、哪个属性里这是构造payload的基础。控制台Console查看JavaScript错误执行一些简单的JS代码进行测试非常方便。Burp Suite社区版虽然前10关可能用不到它的重放、爬虫等高级功能但Burp的代理和拦截功能能让你清晰地看到浏览器发送的请求和服务器返回的响应对于理解数据流向、分析过滤逻辑至关重要。配置好浏览器代理通常是127.0.0.1:8080然后打开Burp的拦截功能你就能看到每个关卡提交数据时的原始HTTP报文。编码工具与思维XSS绕过很大程度上是“编码”与“解析”的博弈。你需要熟悉一些常见的编码HTML实体编码变成lt;变成gt;。URL编码空格变成%20变成%3C。JavaScript Unicode转义alert可以写成\u0061\u006c\u0065\u0072\u0074。 浏览器开发者工具的控制台或者在线编解码网站都是你快速转换的好帮手。准备好这些我们的XSS实战之旅就可以正式开始了。记住我们的目标不是“过关”而是理解每一关背后的安全逻辑。3. 核心原理XSS攻击类型深度解析在开始闯关之前我们必须把XSS的“内功心法”搞清楚。XSS全称是跨站脚本攻击核心在于攻击者能够将恶意的JavaScript代码“注入”到目标网页中并被其他用户的浏览器执行。根据恶意代码的存储和触发方式主要分为三类理解它们对通关至关重要。3.1 反射型XSS一次性的“钓鱼钩”反射型XSS是最常见也往往是Xss-Labs前期关卡的设计重点。它的攻击流程是这样的攻击者构造一个含有恶意脚本的URL然后通过邮件、社交网站等手段诱骗用户点击。当用户点击这个链接时恶意脚本作为请求的一部分比如在查询参数?namescriptalert(1)/script发送到服务器服务器未加过滤就直接将这个参数值“反射”回用户的浏览器页面中并执行。它的特点是“非持久化”。恶意脚本并没有存储在服务器数据库或文件里它像一次性的鱼饵只对点击了特定链接的用户生效。在靶场中你会在地址栏看到你输入的payload直接出现在URL里这就是典型的反射型场景。防御的关键在于对用户输入进行严格的输出编码特别是在将输入放入HTML上下文时。3.2 存储型XSS潜伏的“地雷”存储型XSS的危害性更大。攻击者将恶意脚本提交到网站例如论坛发帖、评论留言、用户昵称服务器未经验证就将其存入数据库。之后任何其他用户访问包含这条数据的页面时恶意脚本都会从服务器加载并执行。它的特点是“持久化”。一次注入长期影响所有访问者。比如著名的“Samy蠕虫”就是利用MySpace的存储型XSS在短时间内疯狂传播。在靶场中如果某一关你提交payload后刷新页面或新开窗口访问攻击依然生效那很可能就是存储型。防御它需要在输入时验证和过滤以及在输出时编码双管齐下。3.3 DOM型XSS客户端的“逻辑漏洞”DOM型XSS比较特殊它的恶意代码执行完全发生在客户端浏览器不经过服务器端处理。攻击利用的是前端JavaScript代码的不安全写法。例如页面上的JS代码使用document.location.hash或document.URL来获取URL片段并直接通过innerHTML或eval()等危险方式写入页面。它的关键在于“客户端的JS解析”。即使服务器返回的响应是安全的但前端JS逻辑不当在客户端动态构建DOM时也会产生漏洞。在靶场中你可能发现提交的参数在服务器响应里看不到但却能触发弹窗这时就要仔细审查页面的JS源代码。防御DOM型XSS需要避免使用innerHTML、outerHTML、document.write()等危险API或者对传入的数据进行严格的清洗。4. Xss-Labs 1-5关基础反射型XSS实战这五关是热身环节旨在让你熟悉最基本的XSS注入点寻找和payload构造。4.1 第一关毫无过滤的“Hello World”第一关通常是最简单的用于建立信心。页面有一个搜索框提示你输入内容。通关步骤与原理分析在输入框尝试输入test提交。观察页面你会发现你输入的内容被原封不动地显示在了页面上。查看页面源代码CtrlU搜索“test”。你会发现类似这样的结构h2 aligncenter您搜索的关键词是test/h2。这说明我们的输入被直接拼接到了HTML标签内部。既然是在HTML标签内部h2标签的内容部分那么直接插入一个script标签是可行的。构造payloadscriptalert(xss)/script。提交成功弹窗。核心要点这一关没有任何过滤是理想化的漏洞场景。它告诉我们寻找注入点的第一步就是看用户输入被放置在了哪个“上下文”中。这里是HTML Body上下文直接插入脚本标签即可。4.2 第二关隐藏在搜索框的注入第二关看起来和第一关一样但直接输入scriptalert(1)/script会发现不成功。页面显示了你输入的代码但没有执行。问题排查与绕过查看源码输入payload后查看页面HTML。你可能会发现你的输入被放在了类似input typetext valuescriptalert(1)/script的位置。这说明我们的输入被放在了HTML标签的属性值里value属性。理解上下文在HTML属性值中script标签不会被浏览器当作标签解析而是当作普通文本。要执行代码需要先闭合当前的属性值和标签。构造payload我们的目标是先闭合value属性的双引号然后闭合input标签再插入我们的脚本。payload可以构造为scriptalert(1)/script。闭合value属性前的双引号。闭合input标签。scriptalert(1)/script插入我们的恶意脚本。提交后查看生成的HTML会变成input typetext valuescriptalert(1)/script。这样script标签就被成功分离出来并执行了。实操心得这一关的关键是上下文切换。你不能想当然地认为输入框里的内容就会出现在页面主体。一定要查看生成的HTML源码确定输入被解析到了哪个具体位置。属性值中的注入通常需要先闭合属性或标签。4.3 第三关单引号的挑战第三关使用第二关的payloadscriptalert(1)/script发现也不成功。输入的内容似乎被原样显示了。深入分析与技巧Burp Suite抓包分析用Burp拦截提交的请求看看数据是否被修改。或者更直接地查看页面源码。源码分析在源码中你可能会发现输入被放在了这样的地方input typetext value$input。注意这里属性值使用的是单引号包裹。调整payload既然属性是单引号我们就需要用单引号去闭合。同时为了闭合标签也需要。因此payload应为scriptalert(1)/script。闭合value属性前的单引号。闭合input标签。后续同上。提交成功弹窗。注意事项在实际渗透测试中你需要灵活判断属性是用双引号、单引号还是不用引号包裹。观察源码或使用Burp查看响应是必须的步骤。一个常见的测试方法是先提交一个单引号或双引号看看页面显示是否异常从而判断包裹情况。4.4 第四关过滤了尖括号怎么办来到第四关尝试之前的payloadscriptalert(1)/script发现失败。查看源码发现尖括号和被过滤或转义了script标签无法构成。绕过策略事件处理器当尖括号被过滤无法构造新标签时我们还可以利用现有HTML标签的事件处理器属性。这些属性如onclick,onmouseover,onload,onerror里面可以写JavaScript代码。寻找可利用的标签查看页面除了输入框是否还有其他标签或者我们的输入是否被放入了一个新的标签里假设输入被放入了一个div或input的value中。构造事件payload假设输入点在input value$input。我们可以构造payload onmouseoveralert(1)。注意开头有一个空格。原理提交后生成的HTML为input value onmouseoveralert(1)。我们通过闭合双引号和插入一个空格添加了一个onmouseover事件。当鼠标移动到这个输入框上时alert(1)就会被执行。你也可以用onfocus事件元素获得焦点时触发payload onfocusalert(1) autofocus。这里还加了autofocus属性让输入框自动获取焦点从而自动触发事件。经验技巧onmouseover需要用户交互而onfocus配合autofocus可以实现自动触发。这是绕过标签过滤的经典方法。常用的还有onload用于img、body等标签、onerror常用于img标签的src错误时触发。4.5 第五关过滤了“script”和“on”事件第五关难度提升。尝试script和 onmouseover都失败了。查看源码发现“script”和“on”这两个关键词可能被替换为空或过滤掉了。高级绕过利用链接与伪协议既然“script”和“on”被过滤我们得寻找其他可以执行JavaScript的HTML属性。a标签的href属性以及iframe,img,svg等标签的某些属性都支持javascript:伪协议。分析注入点确认输入被放置在何处。假设仍在input value$input。构造payload我们可以尝试闭合标签插入一个a标签。Payloada hrefjavascript:alert(1)click/a。闭合value和input标签。a hrefjavascript:alert(1)click/a插入一个超链接其href属性使用javascript:伪协议。点击这个链接就会执行JS。但是如果“script”被过滤javascript:里的“script”也会被干掉。这时可以尝试大小写混淆或双写绕过如果过滤是简单的替换为空。例如a hRefjavaSCRIPT:alert(1)click/a。浏览器对标签和属性名不区分大小写但过滤程序可能只匹配小写。如果还不行可以考虑使用img标签的onerror事件但“on”被过滤了。可以试试img src1 oonnerroralert(1)双写on过滤一个还剩一个或者使用svg等标签。排查思路当payload不生效时首先用Burp或查看源码确认你提交的内容经过服务器处理后变成了什么样子。是关键词被删除、被转义还是被替换成其他字符这决定了你的绕过方向。5. Xss-Labs 6-10关进阶过滤与编码绕过从第六关开始靶场的过滤规则会越来越复杂需要综合运用多种技巧。5.1 第六关大小写绕过与HTML实体编码第六关可能过滤了script、on、src、href等关键词并且可能是不区分大小写的过滤。直接使用之前的payload都会失败。实战绕过测试过滤规则分别提交script、SCRIPT、ScRiPt查看哪个被过滤。如果只有小写被过滤那么大写或大小写混合就可行。PayloadScRiPtalert(1)/ScRiPt。利用HTML实体编码绕过如果标签和事件的关键词被严格过滤另一种思路是输入点是否在某个标签的属性值里并且该属性值支持HTML实体解码例如某些场景下输入会先被HTML实体编码再输出但如果输出点是在a href...里浏览器会对href属性值进行URL解码。这时可以尝试双重编码。一个可能的场景输入被放入a href\$input\。如果我们提交javascript:alert(1)其中的script被过滤。我们可以尝试提交URL编码javascrip%74:alert(1)t的URL编码是%74。如果服务器只做了一次解码或者过滤发生在解码前可能绕过。核心思路这一关训练的是灵活变通。不要死磕一种方法。当直接的关键词被阻尝试1) 大小写变形2) 插入无关字符或标签如scrscriptipt假设过滤是删除script字符串删除后正好拼接成新的script3) 利用其他标签和属性如iframe,embed,object的src4) 编码。5.2 第七关关键字删除与双写绕过第七关的过滤策略可能是发现“script”、“on”、“src”等关键字直接将其删除。例如你输入script服务器处理后变成。双写绕过技巧 如果过滤逻辑是简单的str_replace(script, , $input)那么我们可以利用“双写”来绕过。构造payloadscrscriptiptalert(1)/scrscriptipt。当服务器删除中间的“script”字符串后剩下的部分会拼接成scriptalert(1)/script。同理对于onmouseover可以写成oonnmouseover。删除“on”后剩下onmouseover。对于href中的javascript可以写成javajavascriptscript。实操要点这种绕过方式非常经典在早期的很多Web应用中有效。它的关键在于猜测或发现过滤是“查找并替换为空”的机制。通过查看处理后的输出可以验证这一点。5.3 第八关HTML实体编码与JavaScript Unicode转义第八关可能对输入进行了HTML实体编码。你输入script输出到页面上显示为lt;scriptgt;代码被转义成纯文本无法执行。绕过策略在可执行上下文中利用编码如果输入被编码后放在HTML文本节点中那基本无解。但如果输入被放在一个本就会执行JavaScript的地方比如a hrefjavascript:...中的...部分或者script.../script标签内部情况就不同了。场景假设假设关卡要求你向一个“友情链接”提交URL后端会将你的输入放入a href$input链接/a。直接提交javascript:alert(1)但发现javascript:被过滤或alert被转义。尝试编码绕过浏览器在解析href属性中的javascript:伪协议时会对其中的内容进行URL解码。我们可以对alert(1)进行URL编码javascript:alert%281%29。提交后服务器可能不会对编码后的内容做过滤而浏览器执行时会解码。更高级的JavaScript Unicode转义在script标签内部或javascript:协议中还可以使用Unicode转义序列。例如alert(1)可以写成\u0061\u006c\u0065\u0072\u0074(1)。构造payloadjavascript:\u0061\u006c\u0065\u0072\u0074(1)。如果服务器只是简单匹配alert字符串可能无法识别这种形式而浏览器JS引擎可以正确解析。组合拳甚至可以组合HTML实体和URL编码但这需要精确判断服务器处理数据的顺序和浏览器的解析顺序。5.4 第九关链接验证与协议限制第九关模拟了一个更真实的场景一个“添加链接”的功能。它可能要求你输入一个“合法”的URL即必须以http://或https://开头否则不予通过。绕过思路在“合法”URL中嵌入恶意代码基本尝试直接输入javascript:alert(1)会被拒绝因为不是http/https开头。利用协议混淆尝试http://javascript:alert(1)不行浏览器会将其视为一个指向主机名为javascript的HTTP请求。利用HTML标签解析特性关键在于即使href的值以http://开头我们能否在其后构造可执行的代码通常不行因为http://后面的部分会被当作URL路径。正确解法题目可能检查的是整个字符串是否包含http://而不是是否以它开头。那么我们可以构造javascript:alert(1)//http://example.com。javascript:alert(1)是我们的恶意代码。//在JavaScript中是单行注释。http://example.com是为了通过“包含http://”的检查。提交后生成的链接是a hrefjavascript:alert(1)//http://example.com。点击时浏览器执行javascript:alert(1)后面的//http://example.com被当作注释忽略。另一种思路如果检查是“以http://开头”是否可以构造http://但利用符号等技巧例如http://javascript:alert(1)但现代浏览器对此处理很严格通常不可行。更可能的是利用数据URI协议如data:text/html,scriptalert(1)/script但数据URI协议可能也被过滤。这一关的核心是考察你对输入验证逻辑的绕过以及如何构造一个既能通过后端验证又能在前端被解析为可执行代码的字符串。5.5 第十关隐藏参数与DOM型XSS初探第十关的页面可能看起来没有明显的输入框。但查看网页源代码或许会发现一些隐藏的input typehidden标签或者URL中有一些奇怪的参数如?keywordtestsubmit搜索。通关流程与DOM分析寻找输入点使用Burp Suite抓取页面请求或者仔细观察URL和页面表单。可能会发现一个名为t_link、t_history、t_sort之类的参数。测试参数尝试修改这些参数的值例如将?t_sort123改为?t_sortabc提交后观察页面变化或者查看源码搜索“abc”看你的输入出现在哪里。发现DOM操作通过查看页面引用的JavaScript文件或内联JS你可能会发现类似这样的代码var sort getParameter(t_sort); // 从URL获取参数 document.getElementById(someElement).innerHTML sort; // 不安全地写入页面构造DOM型XSS既然参数值通过innerHTML直接写入了DOM且没有经过过滤那么这就是一个典型的DOM型XSS漏洞。我们可以构造payload?t_sortimg src1 onerroralert(1)。提交后前端JS获取到t_sort的值并将其通过innerHTML插入到页面某个元素中。img标签被解析src指向一个不存在的资源触发onerror事件从而执行alert(1)。DOM型XSS要点这类漏洞的挖掘要求你不仅看服务器返回的HTML更要分析前端JavaScript代码的逻辑追踪用户可控的数据如URL参数、Cookie、本地存储是如何流经危险函数innerHTML,outerHTML,document.write,eval,setTimeout/setIntervalwith string并最终被执行的。防御之道在于避免将不可信的数据传递给这些危险的“接收器”。6. 核心防御策略与安全编码实践通关了前10关我们见识了各种XSS攻击手法。现在从防御者的角度看看如何构建坚固的防线。防御XSS不是单一技术而是一套组合拳。6.1 输入验证与过滤第一道闸门输入验证的原则是“严格且明确”。只接受符合预期格式的数据。白名单优于黑名单不要试图过滤掉所有“坏”的字符如,,因为你很难穷尽所有变形和编码。应该定义什么是“好”的数据。例如用户名只允许字母数字邮箱地址必须符合正则表达式URL必须是以http://或https://开头的合法格式。在服务器端进行客户端验证只是为了用户体验服务器端验证才是安全的关键。攻击者可以轻易绕过客户端JS验证。针对上下文过滤对于富文本内容如文章、评论完全过滤HTML标签可能不现实。可以使用经过严格安全审计的富文本编辑器如CKEditor with its Advanced Content Filter并配置允许的标签和属性白名单。6.2 输出编码最关键的安全屏障输出编码是防御XSS最有效、最根本的手段。其核心是在将不可信的数据输出到不同上下文时对其进行正确的编码使其被解释为数据而非代码。HTML Body上下文如div$userInput/div使用HTML实体编码。将编码为amp;编码为lt;编码为gt;编码为quot;编码为#x27;。在PHP中可用htmlspecialchars($string, ENT_QUOTES, UTF-8)。HTML属性上下文如input value$userInput同样使用HTML实体编码并且属性值一定要用引号括起来。避免使用value$userInput这种无引号或引号不匹配的写法。JavaScript上下文如scriptvar name $userInput;/script这非常危险。应该避免将用户输入直接放入JS中。如果必须需使用JavaScript编码如使用\xHH或\uHHHH进行Unicode转义。更好的做法是将数据放在HTML的>
返回列表