资讯动态

XSS靶场实战:16种绕过技巧从入门到防御全拆解

发布时间:2026/10/19 5:47:46 来源:尧图企业网站定制
新手学XSS最难受的一件事就是教程里到处是零散的payload片段关卡却没人带着过。我在带人入门的时候最喜欢用xss.haozi.me这类闯关式XSS靶场原因很简单——它把抽象的绕过思路变成了一题接一题的实战闯关每个关卡都会逼你换一种姿势构造攻击而闯关目标统一就是弹出alert。这篇文章不是念概念而是把我在这个靶场上一关一关练下来遇到的16种绕过技巧完整拆给你看。适合刚开始碰XSS的安全新人、写页面但没注意过上线的开发者也适合想要快速热身的渗透老手按顺序读练完不说精通至少面对常见过滤心里有底。1. 为什么拿xss.haozi.me做入门靶场选型逻辑与准备工作1.1 一个能“通关”的靶场才是好教练学习XSS最大的误区是以为看懂了“反射型、存储型、DOM型”的分类就等于会了。真正上手以后你才会发现最大的障碍不是不懂概念而是不知道一条payload该往哪里放、过滤规则到底拦了什么、为什么同样的代码在本地能弹窗换个环境就哑火。xss.haozi.me这类靶场解决的就是这个问题。它把练习拆成像游戏一样的连续关卡每关只有一个注入点目标非常统一想办法在任何位置弹出alert。随着关卡推进服务端过滤规则逐渐加码从最基础的直接拼接到封掉script标签、封掉关键字、封掉括号逼着你一层层往上解锁新姿势。这种由易到难的节奏对新手极其友好你不需要一开始就理解全部浏览器解析规则只需要在上一关的基础上多尝试一种绕过思路自然就能感知到“过滤器拦的是哪个环节”。我更愿意把它比作驾校的封闭场地。真实站点是开放道路出事故代价大靶场是圈起来的安全区域你怎么折腾都不会影响别人撞了护栏还能重新来。这种低试错成本的设计决定了它是练习XSS最理想的起点。等你在靶场里把绕过思路练成肌肉记忆再去看真实业务的漏洞会有种“过滤器终于从纸面变成对抗对象”的实感。1.2 动手之前浏览器、控制台和最小知识储备虽然靶场是网页版不要求本地搭环境但准备工作还是有几个点值得做足。首先是浏览器选择。练习XSS有一个很现实的差异不同浏览器的解析规则存在细微差别同一段编码payload在Chrome里能执行换到Firefox可能就变成纯文本。我建议练习期间固定使用Chromium内核的浏览器并且关闭自动更新干扰保证你在靶场里遇到的解析行为是稳定的。靶场答案的通用性也是以主流现代浏览器为基准的。第二件必做的事是打开开发者工具。不要去背快捷键只记住三个面板的用途就行Elements面板用来看注入后的真实DOM结构能直接告诉你输入被拼到了哪个节点Console面板接收JavaScript报错信息payload没弹窗时很多线索都在这里Network面板用来核对请求发出时payload有没有被自动编码。这三个面板配合使用基本上就能覆盖90%的排查场景。我在练习时习惯把开发者工具放在右侧左侧刷新页面触发payload右侧看DOM变化效率比来回切标签页高很多。最后是最小知识储备。不需要系统学完整本Web开发教程但至少要知道HTML标签和属性长什么样、JavaScript的函数调用怎么写、单引号双引号和反引号的区别。这些知识点任何一个前端开发者都熟半路出家的安全爱好者也可以边练边补遇到不认识的事件时现查MDN文档也不丢人。1.3 安全边界这个靶场练的是什么不该练什么说句实在话XSS绕过技巧是典型的攻击视角知识很多人一听“绕过”就兴奋但我必须先划出一条清晰的边界。靶场练习是合法且必要的。xss.haozi.me这类平台本身就是用来做安全教育的你注入的payload只会影响你自己的浏览器会话不会触达其他真实用户。这是攻击性技术学习最安全的形式也是安全社区公认的练习方式。注意这些绕过技巧的用途最好始终定位在漏洞挖掘、编码审计、安全防御建设这些方向。不要做的一件事是拿这些技巧去未授权的真实站点上试。在别人的网站上执行脚本既违反法律又不道德即使只是弹个alert也可能给站点和用户造成损失。我见过有人觉得“我就试一下不搞破坏”但未经授权就是未经授权这在行业里是一条不能越过的红线。练靶场和做授权测试是安全的除此之外任何未经允许的尝试都不应该做。守住这条边界你才能真正把精力放在技术本身。2. 吃透XSS的本质16种绕过技巧到底绕的是什么2.1 一句话版本数据被当成了代码XSS的根因其实很朴素本该作为文本展示的用户输入被拼接进了HTML或JavaScript代码里执行了。想象一个搜索页面把用户输入的关键词原样回显到网页上正常输入“安全测试”时页面显示的是“你搜索的是安全测试”。浏览器把这段文字当成纯文本放进标签内容里。但如果输入的是scriptalert(1)/script而这个输入没有任何处理就被插进HTML文档浏览器就会把尖括号当成HTML标签开始解析脚本自然就执行了。说得夸张一点这就像你在一张写着文字的纸条上混进了一条电脑指令而读纸条的人不仅读了还把指令照做了。理解这个成因的意义在于后面看绕过技巧时方向会很清晰。所有的过滤器本质上都在判断一件事输入内容里有没有“看起来像代码”的部分。而所有的绕过技巧都是在想方设法让“看起来不像代码”的字符在浏览器解析后重新变成代码。这就引出了过滤与解析之间的对抗也就是XSS绕过最核心的战场。2.2 服务端过滤的常见模型黑名单、白名单与转义服务端防御XSS的方式可以归纳成三种模型靶场的每一关基本都建立在其中一种或几种之上。第一种是黑名单过滤。系统维护一个危险关键词列表遇到script、javascript、onerror这些词就删掉或替换成空字符串。这类模型实现简单但缺点也很明显——黑名单永远是不完整的漏掉一个事件属性或一个标签就给了攻击者一条生路。很多绕过技巧本质上就是寻找黑名单没覆盖到的角落。第二种是白名单过滤。只允许特定标签、特定属性、特定协议通过其他一律拒绝。这种方式安全性高很多但要做得严密也难标签属性的组合无穷无尽稍有不慎就会放过svg、math这些冷门标签。第三种是转义处理。把HTML特殊字符转成实体比如把转成lt;、双引号转成quot;让浏览器不再把它们当成代码语法。这种模型看着很严谨但有一个前提必须在正确的上下文做正确编码。在HTML标签内容里转义了却在JavaScript字符串里忘了转义或者在HTML属性里用错了引号类型照样可能被构造出可执行的代码。你不需要在靶场里判断每一关具体用的哪一种模型但要养成这个习惯每次payload失败时想一想它失败在哪一层——是关键字被删了还是尖括号被转义了还是在属性值里引号被吃掉了搞清楚这一点比盲目试一百个payload有用得多。2.3 绕过的本质三种解析器之间的认知差为什么同一个payload在黑名单里出现就会被删放进浏览器又能执行原因在于浏览器的处理过程不是“一把梭”而是由多种解析器分阶段完成的。粗略来说浏览器解析一个HTML文档时会先由HTML解析器把整个文档拆成标签、属性、文本节点遇到JavaScript代码时再由JavaScript解析器去解读脚本语法遇到URL地址时又会由URL解析器处理协议和路径。这三种解析器各自有一套规则而过滤器通常只是用一个正则去扫描原始字符流它看到的是一维的字符串浏览器看到的却是分层的语义。打个比方原始字符#106;#97;在过滤器眼里就是一堆数字和符号但HTML解析器会在属性值里先把实体解码成字母拼出ja如果后面再接上vascript:最终交给URL解析器时它就变成了完整的javascript:协议。过滤器和浏览器看到的内容不一致这个间隙就是绕过的空间。所以16种技巧看着花样复杂底层的逻辑都是同一件事把真正的危险代码藏在过滤器的扫描视野之外让浏览器在逐层解析时再把它们还原出来。理解了这一层你就掌握了XSS绕过的总纲。3. 16种绕过技巧逐个拆解附可复制的payload在动手练之前先看一张总表建立全局认知。这张表我是按照“绕过思路”分的组不是按照难度线性排的因为靶场里同一关往往需要几种思路配合你只有先看全貌才知道该往哪个方向使劲。编号分组技巧名称核心payload思想绕过原理1字符变形大小写混合sCrIpTalert(1)/sCrIpT利用过滤器大小写敏感2字符变形属性内换行/空格拆分img srcx onerror alert(1)利用HTML对空白字符的宽容3字符变形事件处理器换用svg onloadalert(1)黑名单漏掉未被拦截的事件4编码混淆HTML实体编码#x6a;#x61;#x76;#x61;#x73;#x63;#x72;#x69;#x70;#x74;:alert(1)HTML解析器先解码实体5编码混淆URL编码%6a%61%76%61%73%63%72%69%70%74:alert(1)URL解析器先做百分号解码6编码混淆JS Unicode/Hex转义\u0061lert(1)JS解析器识别转义序列7结构裁剪触发词双写拆半scrscriptiptalert(1)/script过滤只做一次递归删除8结构裁剪标签闭合注入新标签svg onloadalert(1)先闭合上下文再注入9结构裁剪注释符干扰正则!--scriptalert(1)/script--黑名单正则被注释结构扰乱10结构裁剪换行回车破坏正则onerror\nalert(1)正则默认不匹配换行符11语法糖反引号无括号调用onerroralert\1模板字符串可隐式调用函数12语法糖伪协议转移iframe srcjava#x09;script:alert(1)协议关键字被Tab/实体拆分13语法糖非script标签场域svganimate onbeginalert(1)黑名单只封script标签14语法糖DOM跳板与拼接onerrorwindow[alert](1)动态属性访问绕过关键词15组合叠加多编码叠加%26%23x6a%3Bavascript多层解码逐层还原16组合叠加终局组合payloadsvg/onloadtop[al%2bert](1)融合闭合、标签、编码、拼接这张表只是索引下面每一组我都给出具体的payload和为什么这么写的解释。你在靶场里遇到问题时可以先定位自己卡在哪种过滤下再回来翻对应的技巧。3.1 字符变形让过滤器认不出关键词技巧1大小写混合这是最基础的绕过适合过滤逻辑简单的情况。script被删了就试Script再不行就试sCrIpT。sCrIpTalert(1)/sCrIpTHTML标准对标签名和属性名不区分大小写SCRIPT和script在浏览器眼里是完全相同的东西。但早期很多黑名单实现只匹配小写关键词没有加i修饰符导致“Uppercase一下”就能轻松绕过。我在带新人时总是先让他们试这个不是因为实用价值高而是为了建立一个意识过滤器写得不严谨到处都是面儿上就能看出来的窟窿。不过要提醒一句现代应用凡是自己写了正则的基本都会带上/i标志大小写绕过在真实场景里已经很罕见了。它的价值更多是入门第一课告诉你“过滤器和浏览器看待输入的方式不是完全一致的”。技巧2属性内换行/空格拆分比大小写稍微进阶一点的变形是把一个完整的危险字符串拆开在中间插入HTML允许的空白字符。HTML规范在解析属性时对属性名与属性值之间的Tab、换行、空格是宽容的。过滤器用正则抓onerroralert这种连续字符串时一旦中间骨节断开匹配就会失败。img srcx onerror alert(1)注意这里的等号两侧空格。在很多过滤器的正则里会直接搜onerror后面紧跟和可执行代码。中间插了空格以后正则要么匹配不上要么匹配出来了但替换时破坏了原来的结构反而给了你新的拼接机会。更极端的写法还有在javascript单词中间塞Tabjava\tscript:alert(1)HTML解析器在属性值里会把这些空白忽略掉最终合起来仍然是合法的协议。这个技巧的启示在于过滤规则如果基于字符序列匹配那么所有“合法但不常见”的字符排列都可能成为突破口。你在靶场里看到某一关过滤了某个词不妨先在词前后插空格、插Tab、插换行各试一遍成本极低收益却经常超预期。技巧3事件处理器换用很多前端防XSS的黑名单总是防得住已知的几个事件属性比如onclick、onerror但事件属性名单实在太多了根本列不完。这一组的思路很好理解不是把一个事件改成花哨的写法而是换一个过滤器没封住的事件。img srcx onerroralert(1) svg onloadalert(1) input onfocusalert(1) autofocus第一行是标准操作img标签的src指向一个不存在的地址时会触发onerror这个事件在XSS里近乎万能。第二行用svg的onload因为SVG也是HTML文档合法的一等公民加载就会触发。第三行利用autofocus自动聚焦触发onfocus连用户交互都不需要。我在练习时有个习惯如果一个payload被防住我会把触发载体换着花样来onerror不行换onloadonload不行换onfocus每换一个都意味着过滤器要重新列一条黑名单。等到后面看到onbegin、onactivate这类冷门事件你就能理解为什么单纯靠黑名单堵事件属性永远是一件吃力不讨好的事。3.2 编码混淆让payload变成“另一串字符”技巧4HTML实体编码这是编码混淆里最经典的一种。HTML解析器在处理标签属性值时会把#x6a;这类实体解码成对应的字符而字符串过滤往往发生在原始字符阶段两边看到的文本根本不一样。img srcx onerror#97;lert(1) a href#x6a;#x61;#x76;#x61;#x73;#x63;#x72;#x69;#x70;#x74;:alert(1)点我/a第一行里#97;代表字母aonerror在解析后实际上是alert(1)但在过滤器眼里引号里只有一串数字符号。第二行更典型整个javascript:协议都用十六进制实体表示浏览器看到href属性时会先做HTML实体解码拼出完整的javascript:alert(1)接着再传给URL解析器。这里有个非常重要的上下文限制HTML实体解码通常发生在标签和属性值中不会发生在script标签的脚本内容里。你在script标签内部写#97;lert(1)浏览器会把它当成一行内含乱码的JavaScript结果大概率是语法报错而不是弹窗。很多人练这个技巧失败就是没分清上下文。技巧5URL编码URL编码的核心思路跟实体编码一样只是解码器换成了URL解析器。浏览器在处理href、src这类URL地址时会先做百分号解码把%6a变成j。a href%6a%61%76%61%73%63%72%69%70%74:alert(1)点我/a iframe src%6a%61%76%61%73%63%72%69%70%74:alert(1)/iframe你可能会疑惑这条payload里的alert(1)没有编码是不是也能被过滤实际应用时看情况通常会把协议部分编码就够了因为过滤器对javascript:这几个连续字符极其敏感而对后面alert(1)的警惕性相对低。当然如果过滤器严到连函数名一起拦就得把alert也编码一层。一个常见坑是URL的百分比编码经常在传输过程中被服务端自动解码导致payload到达浏览器时已经是明文过滤规则又生效了。所以这种技巧能不能过关取决于过滤发生在哪个阶段。靶场里如果在Network面板看到发送的payload被解码了可以试试把百分号本身再编码一次形成双重编码结构。技巧6JS Unicode/Hex转义在JavaScript代码内部\u0061是合法的转义序列表示字母a。这个机制可以被用来绕过对alert这类关键字的字符串匹配。img srcx onerror\u0061lert(1)浏览器在解析JavaScript时会先处理转义序列\u0061lert(1)被还原成alert(1)再交给解释器执行。类似的还有十六进制转义\x61lert(1)以及八进制写法。但要注意十六进制和八进制转义只在字符串字面量中生效用于标识符时可能会报错Unicode转义相对稳一些很多上下文都能用。这个技巧同样受上下文限制它只在JavaScript解析器介入的区域有效放在纯HTML文本里就不会有反应。判断方法很简单先确认你的输入最终落在onerror属性值、script内容这类JS上下文里再考虑用转义序列。3.3 结构裁剪让过滤器找不到完整标签技巧7触发词双写拆半有一种黑名单的实现方式是递归删除危险关键词比如遇到script就删掉而且删的时候会把两段残留拼接起来再删一遍。双写绕过针对的是实现不太严谨的情况过滤器如果只删一次剩下的部分拼接后恰好重新组成完整标签。scrscriptiptalert(1)/script这里我解释一下逻辑。原始字符串里有两个script的相关片段一个是scr后面紧跟script再后面是ipt。如果过滤器把中间的script子串删掉剩下的scr和ipt会被拼成script浏览器解析时正好形成一个完整标签。这类问题在早期的后门防护和WAF规则里很常见因为实现者把“删一次”当成了“删干净”。在靶场里如果你发现输入script被清空而且清空后前后的字符发生了“拼接效应”就应该立刻尝试双写。这不算高深的技巧但对理解正则替换的回调机制很有帮助。技巧8标签闭合注入新标签这是所有XSS实战里最实用的技巧之一。很多过滤场景不是把整个输入当作富文本而是把输入塞进某个属性值里比如value你的输入。这时候想执行脚本得先跳出属性值字符串再造一个新标签。svg onloadalert(1)一个典型的拼接长这样input value你的输入。当你输入的关闭了value属性的引号接着关闭了input标签本身后面的svg onloadalert(1)就成了一个独立的合法标签。解析器看到svg开始就会正常加载并触发onload不需要关心你前面是什么。这个技巧强调一个概念注入不是非得在一个标签内部完成跳出上下文、另起炉灶往往是更干净利落的方案。我在靶场里遇到卡关第一反应往往是看源码搞清楚自己到底被困在什么结构里再决定是先闭合还是后构造。技巧9注释符干扰正则注释符的绕过思路比较清奇它不是靠编码而是靠破坏过滤正则的匹配结构。HTML和JavaScript的注释形态很多!-- --、!-- --之后跟的--、JavaScript里的/* */和//都可能被利用。!--scriptalert(1)/script--如果过滤器只是简单地把包含script的整段内容替换掉而你的payload前缀是!--那么匹配时可能连着注释符一起处理结果留下的某些片段在浏览器里被当成了插在注释后的新结构重新恢复了语义。更常见的是单行注释符//被用在URL或脚本拼接中将前一行有危险的语句注释掉让payload重新拼接。这种技巧在靶场里属于思路拓展型练它不是为了天天用而是为了打破“过滤器会发现所有代码形态”的错觉。注释符在真实代码里到处都是过滤规则如果对它们没做专门处理漏洞往往就藏在最不起眼的地方。技巧10换行回车破坏正则正则默认匹配的一个陷阱是很多正则表达式的.和字符类不会匹配换行符而且整个匹配往往只作用于单行文本。攻击者如果能在payload的敏感位置插入换行或回车过滤器就会把它当成两行内容分别处理可能漏掉关键拼接。img srcx onerror alert(1)这里在onerror和alert(1)之间插了一个换行。有些黑名单正则只抓onerroralert这种连续字符串换行一插入就失配。但浏览器在解析HTML属性值时会把换行当作普通空白处理最终仍然是合法的onerror触发。使用这个技巧时要留意某些服务端框架会自动规范化换行符比如把\r\n统一处理导致注入的换行变成单个\n后仍然在正则视野里。靶场里如果发现换行payload被吞了可以改试Tab或回车得多试几种空白字符的组合。3.4 语法糖与场域转移让函数调用不露痕迹技巧11反引号无括号调用有些过滤规则会把alert(1)的括号当成攻击信号见到(就拦。应对办法之一是避开括号利用ES6的模板字符串语法字符可以被反引号包裹而函数名后加模板字符串会被解释为以模板内容为参数的函数调用。img srcx onerroralert1这里alert\1等价于alert(1)只是没有出现括号。你在靶场里如果发现过滤规则拦括号这招往往立竿见影。还可以配合${}表达式做更多操作比如alert${0}这种写法但新手先记住反引号这个形态就够了。有一个容易踩坑的地方反引号调用会传入模板字符串对象而非常规字符串在只验证参数值是否相等的过滤器里可能出问题但用于弹窗演示是完全没问题的。技巧12伪协议转移HTML里能执行JavaScript的途径不止script标签javascript:伪协议也是老牌通道。很多黑名单死死盯着script标签却忘了a的href、iframe的src都可以加载javascript:代码。a hrefjavascript:alert(1)点我/a iframe srcjavascript:alert(1)/iframe利用这个技巧时首先要确认协议关键字javascript:本身没有被过滤。如果被过滤了可以尝试在java和script之间插入Tab、换行或HTML实体。我在靶场里碰到过好几次过滤器把javascript整个词拉黑但看到java#x09;script这种带实体的写法就直接放过了因为浏览器解析后会把它还原成标准协议。注意javascript:协议在Chrome里对iframe有时不生效换成object datajavascript:alert(1)也能做一个备用方案。伪协议家族的思路就是脚本执行不只一条路封了一条就换另一条路。技巧13非script标签场域XSS执行脚本的载体远远不只是script标签。SVG、MathML这些XML系标签同样支持事件属性而且互联网上大量应用的过滤器只维护HTML标准标签列表根本不会考虑它们。svg onloadalert(1) svganimate onbeginalert(1) attributeNamex dur1s mathmtextimg srcx onerroralert(1)/math第一行的svg不需要闭合直接在开始标签里写onload就能触发。第二行用SVG动画元素animate的onbegin事件这个属性极冷门被列入黑名单的概率极低。第三行是MathML里嵌套图片思路一样标签不同事件属性照常生效。练习这组技巧时我建议你专门建一个清单把别忘了的标签都记下来svg、math、iframe、object、embed。这个清单在真实测试中很有用因为业务后端做富文本过滤时经常只允许p、img、a这类常见标签却对svg类标签睁一只眼闭一只眼。技巧14DOM跳板与拼接最后一组语法糖是通过JavaScript的语法特性动态构造出目标代码。过滤器通常只拦截明文字符串比如alert但如果你把alert拆成al ert在过滤器的原始字符流扫描里就看不到完整关键字了。img srcx onerrorwindow[alert](1)这里先用字符串拼接拼出alert再用方括号访问window对象的属性等价于window.alert(1)。类似的还有top[alert]、parent[String.fromCharCode(97,108,101,114,116)](1)这类写法。后者甚至完全不用字母a、l、e、r、t可以从字符串编码函数动态生成。这种技巧对过滤器的杀伤力很大因为它直接把攻击代码从“字符串匹配可见”变成了“运行时才算出结果”。但也不是没有代价代码变长、可读性降低而且如果过滤器连方括号和加号的组合都限制就得考虑更复杂的拼接方式。3.5 组合与叠加终局payload怎么搭技巧15多编码叠加打了前面的基础这一层就是“把多种编码叠在一起”。浏览器对URL地址的处理是一条链HTML解析器先做实体解码URL解析器再做百分号解码如果最终进入JavaScript上下文JS解析器还会处理Unicode转义。过滤器如果只解码一层多层编码就能骗过它。a href%26%23x6a%3Bavascript:alert(1)点我/a我来拆这条payload%26是的URL编码%23是#的URL编码%3B是;的URL编码。URL解析器先解码这层得到#x6a;avascript:。紧接着HTML解析器再对属性值做实体解码#x6a;变成j拼起来就是javascript:。就这样过滤器如果只检查一层看到的只是乱码。练习多编码叠加的关键是脑海里要有清晰的解码顺序图。你先想清楚输入最终要落在哪个上下文再倒推需要做几层编码。顺序一旦搞反浏览器也会解码失败payload就会变成普通文本。技巧16终局组合payload最后一招是把前面多个技巧同时塞进一条payload。这不是为了炫技而是因为真实场景的过滤器往往是“层层设防”单靠大小写会被正则拦截单靠编码可能被解码一次单靠SVG可能被白名单禁止。这时候只有组合拳才可能打通整条链路。svg/onloadtop[al%2bert](1)逐层看负责闭合前面可能的单引号、双引号和标签svg/onload利用SVG开始标签自带事件top[al%2bert]把alert拆成两段并拼接%2b是的URL编码最终的(1)负责执行。这里揉进了标签闭合、非script标签、字符串拼接、URL编码四种技巧。哪怕过滤器封了最外层的某些特征只要内层哪一环没封严payload就有机会复活。在靶场里练习组合payload时一个实用做法是打印出来贴显示器旁逐项标注每段的作用。等你能随手写出这种组合说明你已经不是背payload的初学者了而是能边构造边推断过滤器的防守盲区了。4. 靶场通关中的高频问题与排查思路4.1 payload没触发先按这个顺序查练习时最磨人的环节就是payload写好了但页面毫无反应。我的排查顺序一直固定推荐新手照抄。第一步看最终DOM。在Elements面板里搜索你输入的payload片段确认它有没有被完整拼接还是被截断、转义、插入了额外字符。很多时候payload没生效只是因为它根本没落在你以为的位置。第二步看Console报错。如果拼接位置没问题那Console通常会有线索Uncaught SyntaxError说明JavaScript语法不对is not defined说明函数名被拼错或被过滤改掉了。按报错去反推远比瞎试高效。第三步看Network面板。查看请求发送时的实际内容如果发现你的变成了%3C说明在到达过滤逻辑之前就被浏览器或框架自动编码了这时候要调整的方向不是绕过策略而是编码方式。第四步逐层简化。把payload改成最朴素的scriptalert(1)/script如果这个都不触发问题多半出在上下文拼接而不是过滤规则太强。如果朴素版本能触发再逐步添加变形技巧每一步都能确认哪一层过滤在起作用。4.2 浏览器差异你以为该执行其实没有在本地Chrome里能执行的payload换个浏览器可能完全没反应这是练习XSS时必须接受的现实。一个典型例子是javascript:协议配合iframe的使用Chrome对iframe的src执行javascript:协议有严格限制而其他浏览器行为不同。另一个常见差异是HTML实体解码的范围某些浏览器在属性值里解码、在脚本内容里不解码另一些浏览器则可能放宽限制。还有一个坑是禁用JavaScript的扩展插件或隐私模式会直接导致所有事件类payload静默失败。所以我在靶场里一直坚持“以单一浏览器为准”。你不同时在两个浏览器里测试两个版本就不要轻易下结论说某个技巧失效。等到了真实项目测试阶段浏览器兼容性反而是你的武器——某些过滤规则在旧版浏览器里就是会被更宽松的解析绕过这一点在写报告时也值得单独标注。4.3 从靶场到防御方这16种绕过带来的防护清单靶场练完最值钱的收获不是能弹几个alert而是获得了一套防御视角。每学会一种绕过技巧我都建议顺手把它翻译成一条防御措施回头写报告或做code review时会非常有底气。输出编码必须区分上下文。在HTML标签内容里用HTML实体编码在属性值里用属性编码在JavaScript字符串里用JS编码在URL里做URL编码。用一套模板走天下的方案几乎必然会在某个上下文里漏出缝隙。过滤策略优先走白名单。与其想办法穷举危险标签和危险事件不如明确允许哪些标签、哪些协议、哪些事件剩下的全部按不安全处理。白名单写起来确实更烦但对抗成本远低于黑名单。CSP是最后一道防线别漏掉。给页面设置script-src规则限制内联脚本和远程脚本来源即使XSS注入成功攻击者也很难加载真正的恶意代码。靶场里练出来的十六般武艺最终要防的其实就是这种“即使有漏洞也跑不动”的状态。5. 我从这套练习里总结的三个关键建议5.1 别背payload背解析流程我见过不少人把网上流传的payload仓库当宝典遇到题目就一个个复制粘贴。这样练下来运气好能通关但换个新靶场立刻抓瞎。真正能迁移的能力是对解析流程的预判当你看到一个输入点脑子里应该自动浮现出它最终落在HTML文本、属性值、HTML注释、JavaScript代码还是URL协议的哪一个区域再根据区域特征去构造payload。靶场里的16种技巧只是这条思考链上的一些常用节点学会推演节点之间的关系才是长期有用的功夫。5.2 给自己建一个payload测试盒练这个靶场的过程其实是一个不断试错、积累“样本”的过程。我建议你把自己的payload逐步分类存档形成一个小型本地测试盒每关通过的payload和失败原因都记录下来。我自己的文件里会分四栏原始payload、成功场景、失败场景、失败原因。比如img srcx onerroralert(1)在某一关能成功换一关因为img被白名单禁了而失败这个对照记录就是最有价值的经验库。以后再遇到类似的过滤规则翻一翻记录基本就能定位方向省去大量重复劳动。5.3 把这16种技巧转成防御自测清单练完之后不要满足于“我会绕了”。把每一组技巧翻译成检查项例如是否所有输出点都区分了上下文是否允许svg这类非白名单标签脚本调用是否能通过拼接绕过关键词在你自己负责的页面上跑一遍这套自测等于把攻击者的思路提前堵死。我在做完靶场之后最大的感受是真正的精通不是会写花哨payload而是闭着眼睛就能把“过滤器的破绽”和“浏览器的解析路径”在脑子里对齐。做到这一步再回头看xss.haozi.me这类靶场的每一关都会觉得它不是题目而是一面镜子照出来的是你对Web解析机制的理解到底有多深。这套流程走下来你已经掌握的不只是16种技巧更是一套应对绕过问题的思考框架往后的路无非是遇到新场景、补充新样本继续把这套框架磨得更锋利。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑