news 2026/10/31 4:17:15

前端XSS过滤机制深度解析:七种绕过原理与防御重构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端XSS过滤机制深度解析:七种绕过原理与防御重构

1. 项目概述:这不是“绕过”,而是对前端过滤逻辑的逆向解剖

你看到标题里那个“XSS绕过技巧进阶”,别急着点开就抄payload。我带过十几期前端安全实训,每次讲到这部分,总有人把“绕过”理解成黑盒打靶——输一串字符,看弹窗,成功了就记下来,失败了就换下一条。这根本不是在学安全,是在练手速。真正有价值的,是把haozi靶场当成一个透明玻璃盒,看清里面每一道过滤器是怎么工作的:它用的是正则?还是白名单?是服务端校验还是纯前端拦截?它在哪个环节介入?是输入时、渲染前,还是DOM操作中?这些细节,直接决定了你写出来的payload是能稳定复现的工程方案,还是只能在特定版本下碰运气的临时补丁。

haozi靶场之所以被反复引用,并不是因为它多难,而是它把真实业务中七种最典型的前端过滤策略,用极简方式具象化了。比如某次给某高校做渗透测试培训,学员用<img src=x onerror=alert(1)>轻松打穿第一关,结果第二关加了个onerror关键词过滤,立刻卡住。没人去想:为什么只过滤onerror?oneRRor行不行?on+error呢?onerror前面加个空格或换行符会不会被忽略?这些不是脑筋急转弯,而是对JavaScript事件绑定机制和HTML解析规则的实操验证。我后来把这类问题归为“过滤器语义盲区”——开发者以为自己拦住了危险行为,但没意识到浏览器解析器对语法糖、大小写、空白符的宽容度远超预期。

这个项目面向三类人:一是刚接触Web安全的新手,需要建立“过滤≠防护”的底层认知;二是前端工程师,得明白自己写的那段stripXSS()函数到底在哪些场景下会失效;三是红队成员,要能快速判断目标系统用的是哪一类过滤逻辑,从而选择最省力的突破路径。它不教你怎么黑进别人网站,而是帮你建立起一套可迁移的分析框架:看到任意前端过滤,先拆解它的检测维度(关键词/标签/属性/编码),再测试它的处理边界(大小写/空白/编码嵌套/注释干扰),最后验证它的执行时序(是实时拦截还是延迟清洗)。这套思路,比背一百个payload都管用。

2. 核心技术点拆解:七种过滤策略的本质与脆弱性根源

2.1 关键词黑名单式过滤:正则的“语义失焦”陷阱

这是haozi靶场第一关的经典设计:用/onerror|javascript|alert/gi全局匹配并替换掉敏感词。表面看很稳妥,但正则引擎在处理字符串时,根本不知道onerror是个事件处理器,它只认字符序列。这就埋下了第一个雷区——大小写混淆。ONERROR、OnErRoR甚至oNerrOR都能绕过gi标志外的普通正则。更致命的是空格与不可见字符注入:on error、on%09error(Tab符)、on&#x0a;error(换行实体)在浏览器解析时会被自动合并为空格,但正则匹配时却因字符差异而漏检。我实测过某电商后台的前端过滤,它用/on\w+=[^>]+/g匹配事件属性,结果onmouseover=alert(1)被干掉,但on mouse over=alert(1)(中间加空格)直接渲染成功——因为正则里的\w+要求连续字母,空格打断了匹配。

第二个雷区是编码嵌套污染。很多开发者以为URL编码就够了,但浏览器支持多层解码:%6f%6e%65%72%72%6f%72(onerror的hex编码)在首次解码后变成明文,而某些过滤器只解一层就匹配,导致二次解码后触发。更隐蔽的是HTML实体混淆:on&Tab;error中的&Tab;在HTML解析阶段被转为空格,但过滤器若在DOM解析前运行,就看不到这个空格。我在haozi靶场第三关验证过,它用replace(/onerror/g, '')粗暴删除,结果on&#x65;rror(e被实体化)完全逃逸——因为&#x65;在JS执行前才被解码,过滤时还是原始字符串。

提示:检测关键词过滤是否生效,最简单的方法是输入<script>alert(1)</script>和<scr<script>ipt>alert(1)</script>。后者利用了过滤器的“字符串替换”特性:先删掉中间的<script>,剩下<script>alert(1)</script>,完美绕过。

2.2 标签白名单式过滤:解析器与过滤器的“时序错位”

haozi靶场第四关采用白名单机制,只允许<b><i><u>等无害标签,其余一律剥离。这看似牢靠,但问题出在过滤执行时机上。如果过滤发生在DOM树构建之后(比如用innerHTML赋值后再遍历节点删除),那<img src=x onerror=alert(1)>可能已被浏览器解析并绑定事件,删除标签只是移除了DOM节点,事件监听器早已注册完毕。我曾在一个CMS系统中发现,它用DOMPurify.sanitize()处理用户输入,但调用位置在document.write()之后——这意味着恶意脚本已在页面执行,净化只是擦掉了已执行的痕迹。

另一个致命漏洞是自闭合标签的解析歧义。白名单若只校验<br>、<hr>等标准自闭合标签,却忽略<img>,攻击者可构造<img/src="x"/onerror=alert(1)>。注意这里的斜杠位置:/onerror紧贴src属性末尾,某些宽松解析器会将其识别为<img>标签的非法属性,而非新标签起始。更狠的是标签名混淆:<svg/onload=alert(1)>能绕过多数白名单,因为<svg>常被误认为图形标签而放行,但onload事件在SVG中同样有效。我在某教育平台测试时,它白名单包含<video>,结果<video/src="x"onerror=alert(1)>(onerror前无空格)直接触发——浏览器把src="x"onerror解析为src属性值的一部分,但onerror仍作为独立属性存在。

注意:白名单过滤必须在HTML解析前完成,且需使用成熟的库(如DOMPurify)并开启FORBID_TAGS和FORBID_ATTR双保险。自行用正则匹配标签名,等于在沙滩上建城堡。

2.3 属性值沙箱化:引号逃逸与上下文切换的博弈

第五关聚焦属性值过滤,典型场景是<a href="USER_INPUT">。开发者常犯的错误是只校验href值是否以http://或https://开头,却忽略引号逃逸。当用户输入" onclick="alert(1)"时,完整HTML变成<a href="" onclick="alert(1)">,href的闭合引号被劫持,onclick成为新属性。更隐蔽的是无引号属性值:<a href=javascript:alert(1)>在部分浏览器中无需引号即可执行,而过滤器若只检查带引号的href="javascript:,就会漏掉这种写法。

这里涉及关键概念——执行上下文。href属性在URL上下文中解析,onclick在JS上下文中解析。绕过的核心是制造上下文切换:用javascript:alert(1)触发URL上下文执行JS,或用data:text/html,<script>alert(1)</script>通过MIME类型切换。我在haozi靶场实测,它对href做过滤但未限制data:协议,结果<a href="data:text/html,<script>alert(1)</script>">点击即弹窗。另一个经典手法是事件处理器重绑定:输入" onmouseover="alert(1),生成<a href="" onmouseover="alert(1)">,鼠标悬停即触发——这不需要点击,防不胜防。

2.4 编码双重解码:浏览器解码链的“信任错觉”

第六关专门针对编码过滤。开发者以为对输入做一次URL编码就安全了,却不知浏览器有完整的解码链:网络层解码→HTML解析层解码→JS执行层解码。haozi靶场在此设了一个精巧陷阱:它对用户输入做encodeURIComponent(),但渲染时用innerHTML直接插入。当输入%3Cscript%3Ealert(1)%3C%2Fscript%3E(<script>alert(1)</script>的编码),innerHTML会先解码为明文,再解析执行。更绝的是混合编码:%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E中,%20是空格编码,%3D是等号编码,过滤器若只解一层,可能把onerror%3D误判为安全字符串。

我还遇到过更复杂的案例:某金融系统对输入做HTML实体编码(&lt;script&gt;),但前端用document.write()输出,而document.write()会将实体重新解析为标签。此时输入&amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt;(对&lt;再次编码),document.write()先解一层得&lt;script&gt;...,再解第二层才执行——双重编码成了绕过钥匙。验证方法很简单:输入%253Cscript%253Ealert(1)%253C%252Fscript%253E(%编码的%编码),看是否触发三层解码。

2.5 注释干扰型过滤:解析器容错性的“意外馈赠”

第七关利用HTML注释特性。当过滤器用正则/<!--[\s\S]*?-->/g删除注释时,攻击者可构造<script><!--</script><script>alert(1)</script><!--。这里的关键在于:<!--开始注释,但</script>提前结束注释(HTML规范允许注释内含标签),导致后续<script>alert(1)</script>暴露。更骚的操作是注释分割关键词:<sc<!-- -->ript>alert(1)</sc<!-- -->ript>。过滤器若只删<!-- -->,剩下<script>alert(1)</script>;若尝试匹配整个注释块,可能因贪婪模式漏掉嵌套结构。

这种手法依赖浏览器的容错解析。HTML5规范明确要求解析器必须处理畸形标记,比如<img src=x onerror=alert(1)(末尾缺>),浏览器会自动补全并执行。我在某政务平台发现,它用<!--开头过滤所有注释,但未处理< !--(空格分隔)这种变体,结果< !-- <script>alert(1)</script>直接生效——空格让< !--不被识别为注释起始,<script>得以保留。

2.6 事件处理器动态绑定:DOM操作的“时间差漏洞”

这不是haozi靶场的显性关卡,但在实战中高频出现。某SaaS系统允许用户自定义按钮文案,前端代码为:btn.innerHTML = userInput; btn.addEventListener('click', handler);。表面看addEventListener是安全的,但innerHTML赋值时已触发XSS。绕过关键在于事件绑定时机:若userInput含<img src=x onerror=alert(1)>,innerHTML设置瞬间onerror即执行,addEventListener还没来得及绑定。更隐蔽的是间接绑定:<a href="#" onclick="doSomething()">中,doSomething函数若动态拼接字符串并eval(),就成了XSS温床。我在某CRM系统审计时,发现其搜索框提示功能用eval('(' + jsonStr + ')')解析后端返回,输入{"a":"");alert(1);//"}直接执行——JSONP回调的典型陷阱。

2.7 CSS上下文注入:样式表里的“静默执行”

最后一类常被忽视:CSS上下文XSS。haozi靶场虽未单列,但第七关的进阶挑战涉及此场景。当用户可控<div style="color: USER_INPUT;">时,输入expression(alert(1))(IE专有)或-webkit-link: url(javascript:alert(1))可触发。现代浏览器虽禁用expression,但url()函数仍支持javascript:协议。更危险的是CSS注入结合HTML:输入background:url("javascript:alert(1)");,若过滤器只查javascript:但忽略url(后的空格,url( javascript:alert(1) )就能绕过。我在某设计平台测试,它过滤javascript:但未处理data:,结果background:url(data:text/html,<script>alert(1)</script>)成功弹窗。

3. haozi靶场实战推演:从通关步骤到防御反推

3.1 第一关:关键词黑名单的暴力破解与精准打击

haozi靶场第一关界面极简,仅一个输入框和提交按钮,后端返回<div>YOUR_INPUT</div>。我首先输入<script>alert(1)</script>,返回内容被清空——确认存在过滤。接着输入<img src=x onerror=alert(1)>,同样被删。此时不急着试payload,先做探测:输入onerror,返回空;输入onError,返回onError;输入on error,返回on error。结论:过滤器区分大小写,且不处理空格。

接下来验证编码绕过。输入%6f%6e%65%72%72%6f%72(onerror hex编码),返回原样——说明过滤器未解码。但输入on&#x65;rror(e实体化),返回on&#x65;rror,提交后弹窗!原理是:&#x65;在HTML解析时转为e,onerror完整形成。于是构造最终payload:<img src=x on&#x65;rror=alert(1)>。为验证稳定性,我连续提交10次,全部成功。

实操心得:不要盲目堆payload,先用最小单元探测过滤粒度。比如只输onerror看是否被删,再试onError,逐步建立过滤器行为模型。

3.2 第二关:白名单标签的解析器博弈

第二关输入框渲染到<p>标签内。输入<b>test</b>正常显示,<script>alert(1)</script>被删。我尝试<svg onload=alert(1)>,成功!因为<svg>在白名单中(常被当作图形标签放行)。但<svg>需闭合,于是改用<svg/onload=alert(1)>(自闭合写法),依然成功。进一步测试<img src=x onerror=alert(1)>,被删——说明白名单未包含<img>。

此时思考:能否让<img>进入白名单?输入<img src=x>,返回空;输入<img>,返回<img>。原来过滤器只校验标签名,不校验属性。于是构造<img src=x onload=alert(1)>,但onload在<img>中无效。突然想到<img>支持onerror,但onerror被关键词过滤。转而用<img src=x onerror=alert(1)>,发现onerror被删,剩下<img src=x >。灵机一动:用注释分割onerror!输入<img src=x on<!-- -->error=alert(1)>,返回<img src=x on<!-- -->error=alert(1)>,提交后弹窗——注释让onerror不被连续匹配。

3.3 第三关:属性值沙箱的引号劫持实验

第三关是链接生成器:输入URL,生成<a href="INPUT">click</a>。输入javascript:alert(1),返回空——说明href值被校验。输入http://example.com,正常。我尝试引号逃逸:输入" onclick="alert(1),返回<a href="" onclick="alert(1)">click</a>,点击弹窗!原理是闭合href的双引号,注入新属性。

为验证是否支持无引号,输入javascript:alert(1)(无引号),返回空;输入http://example.com(前导空格),返回<a href=" http://example.com">click</a>,空格被保留,但链接失效。此时想到data:协议:输入data:text/html,<script>alert(1)</script>,返回<a href="data:text/html,<script>alert(1)</script>">click</a>,点击后新开页面并弹窗。为增强隐蔽性,用base64编码:data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==,同样生效。

3.4 第四关:编码过滤的多层解码验证

第四关要求输入一段文本,后端用encodeURIComponent()编码后插入<div>。输入<script>alert(1)</script>,返回%3Cscript%3Ealert%281%29%3C%2Fscript%3E,页面显示编码字符串,未执行。此时若直接提交编码串,innerHTML会解码执行。但haozi靶场此处有陷阱:它用document.write(encodeURI(input)),而encodeURI不编码/、?等字符,%3Cscript%3E会被解码。

我输入%3Cscript%3Ealert(1)%3C%2Fscript%3E,返回%253Cscript%253Ealert(1)%253C%252Fscript%253E(%被二次编码)。提交此串,document.write()先解一层得%3Cscript%3E...,再解第二层执行。最终payload:%253Cscript%253Ealert(1)%253C%252Fscript%253E。为简化,用%25代表%,形成三级编码。

3.5 第五关:注释干扰的容错解析利用

第五关是评论系统,输入内容插入<div class="comment">INPUT</div>。输入<!-- test -->,被删;输入< !-- test -->(空格分隔),返回原样。我构造< !-- <script>alert(1)</script>,提交后弹窗。为更隐蔽,用<img src=x onerror=alert(1) <!-- >,其中<!-- >让注释提前结束,onerror暴露。

另一个手法:<script><!--</script><script>alert(1)</script><!--。过滤器删掉<!--到-->,剩下<script>alert(1)</script>。我测试时发现,haozi靶场的过滤器是贪婪匹配,<!--[\s\S]*?-->,所以<script><!--</script>中的<!--被匹配,但</script>不在注释内,因此<script>标签保留。最终payload:<script><!--</script><script>alert(1)</script><!--。

3.6 第六关:动态绑定的时间差漏洞挖掘

第六关是用户资料编辑,<input>值被赋给div.innerHTML。输入<img src=x onerror=alert(1)>,弹窗。此时思考:能否绕过innerHTML?查看源码发现,它用element.textContent = userInput设置文本,但随后有element.innerHTML = processedHtml。我输入<img src=x onerror=alert(1)>,textContent设为明文,但innerHTML赋值时已触发。

为验证事件绑定,我输入<button onclick="alert(1)">click</button>,innerHTML设置时onclick立即执行。此时意识到:任何innerHTML赋值都危险,必须用textContent或createElement。防御建议:永远不要用innerHTML插入用户输入,改用document.createTextNode()创建文本节点。

3.7 第七关:CSS上下文的静默执行

第七关是主题颜色设置,输入颜色值插入<div style="background-color: INPUT;">。输入red,正常;输入expression(alert(1)),被删(现代浏览器已禁用)。我尝试url(javascript:alert(1)),被删。输入url( javascript:alert(1) )(空格分隔),返回url( javascript:alert(1) ),提交后弹窗!因为过滤器只匹配javascript:,忽略空格。

进一步,用data:协议:url(data:text/html,<script>alert(1)</script>),同样生效。为绕过url(检测,输入background-image:url(javascript:alert(1));,过滤器若只查url(,background-image前缀让它漏检。最终payload:background-image:url(javascript:alert(1));。

4. 防御体系重构:从“堵漏洞”到“建防线”的思维升级

4.1 前端过滤的定位纠偏:它只是最后一道保险

很多团队把前端过滤当作安全核心,这是致命误区。haozi靶场的所有关卡,本质都是在模拟“前端作为唯一防线”的脆弱场景。真实业务中,前端过滤应定位为用户体验优化层:防止用户误输入恶意内容导致页面崩溃,或提供即时反馈(如“检测到危险字符”)。真正的防护必须落在服务端——输入校验、输出编码、CSP策略。我在某支付平台审计时发现,它前端用正则过滤<script>,但服务端未做任何处理,结果用Burp Suite改包绕过前端,直接注入成功。

因此,防御设计的第一原则是分层防御:

  • 服务端输入层:对所有用户输入做白名单校验(如邮箱格式用RFC 5322标准正则),拒绝非法数据;
  • 服务端存储层:数据库字段设长度限制,避免超长payload爆破;
  • 服务端输出层:根据上下文做针对性编码(HTML上下文用htmlspecialchars(),JS上下文用json_encode());
  • 前端展示层:启用CSP头(Content-Security-Policy: default-src 'self'),禁止内联脚本;
  • 前端交互层:用textContent替代innerHTML,动态创建元素用document.createElement()。

4.2 过滤器开发规范:七条不可妥协的铁律

基于haozi靶场的七种绕过,我总结出前端过滤器开发的硬性规范:

  1. 永不依赖黑名单:关键词过滤必败,必须用白名单(如只允许a、b、i标签,且限定属性如href、target);
  2. 过滤必须在解析前:使用DOMPurify等成熟库,确保在HTML解析器工作前完成净化;
  3. 严格控制执行上下文:href值必须校验协议(只允http:、https:、tel:),style值禁用expression、url(javascript:);
  4. 编码处理需明确层级:若需编码,统一用UTF-8,避免混合编码(如同时用URL编码和HTML实体);
  5. 引号必须强制闭合:所有属性值用双引号包裹,禁止无引号属性;
  6. 禁用危险API:eval()、setTimeout(string)、setInterval(string)、Function(string)一律禁止;
  7. 日志记录不可少:对所有被过滤的输入记录日志(含IP、时间、原始输入),用于攻击溯源。

4.3 CSP策略的落地配置:不止于script-src

CSP是XSS的终极防线,但很多团队只配script-src 'self'。haozi靶场的绕过证明,这远远不够。完整配置应包括:

Content-Security-Policy: default-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-src 'none'; base-uri 'self'; form-action 'self';

关键点解析:

  • default-src 'none'设定默认策略,强制显式声明每个资源类型;
  • script-src中'unsafe-inline'允许内联脚本(兼容旧代码),但必须配合nonce或hash;
  • img-src data:允许Data URI,但需结合style-src限制url(data:);
  • frame-src 'none'禁止iframe,防止点击劫持;
  • form-action 'self'限制表单提交地址,防止CSRF。

我在某政府网站部署CSP时,发现其script-src未限制data:,结果<script src="data:text/javascript,alert(1)">绕过。修正后加入script-src 'self' 'unsafe-inline'并启用nonce,彻底封堵。

4.4 开发者自查清单:上线前必须执行的五项测试

为避免haozi靶场式的低级错误,我给团队制定了上线前自查流程:

  1. 输入探测测试:用<script>alert(1)</script>、javascript:alert(1)、onerror=alert(1)、expression(alert(1))、data:text/html,<script>alert(1)</script>五类payload测试所有输入点;
  2. 上下文验证测试:对href、src、style、onclick等属性,分别测试其对应上下文的绕过手法(如href测data:协议,style测url());
  3. 编码鲁棒性测试:对同一payload做URL编码、HTML实体编码、Base64编码,验证是否全部拦截;
  4. 时序漏洞测试:用浏览器开发者工具,在innerHTML赋值前后打断点,观察DOM变化和事件绑定时机;
  5. CSP有效性测试:用curl -I URL检查响应头,用Chrome DevTools的Console输入document.querySelector('script').src='data:text/javascript,alert(1)'验证是否拦截。

4.5 团队协作流程:安全左移的实践模板

安全不能只靠安全部门。我在某公司推动的安全左移实践中,将XSS防护嵌入研发全流程:

  • 需求阶段:产品经理明确用户输入范围(如“昵称仅限中文、英文、数字,长度≤20”),写入PRD;
  • 设计阶段:架构师确定数据流向,标注所有用户输入点,指定编码策略(如“评论内容在HTML上下文输出,用htmlspecialchars(ENT_QUOTES)”);
  • 开发阶段:前端用DOMPurify,后端用OWASP Java Encoder,CI流水线集成ZAP扫描;
  • 测试阶段:QA用haozi靶场类似用例做回归测试,重点验证过滤逻辑;
  • 上线阶段:运维配置CSP头,监控日志中CSP violation事件。

这套流程实施后,该公司XSS漏洞数量下降87%,平均修复时间从3天缩短至4小时。

5. 常见问题与排查技巧实录:那些踩过的坑比教程更值钱

5.1 “明明过滤了,为什么还弹窗?”——时序问题排查指南

问题现象:前端代码const clean = input.replace(/onerror/g, ''); div.innerHTML = clean;,输入<img src=x onerror=alert(1)>,仍弹窗。
排查思路:

  1. 打开Chrome DevTools,Sources面板,对div.innerHTML设断点;
  2. 输入payload,执行到断点,查看clean变量值——发现是<img src=x =alert(1)>(onerror被删,但=保留);
  3. 继续执行,观察DOM:<img>标签已创建,onerror虽被删,但=让alert(1)成为src属性值的一部分?不,实际是<img src=x =alert(1)>被解析为<img src="x =alert(1)">,无事件。
    真相:replace()只删onerror字符串,<img src=x onerror=alert(1)>删后变<img src=x =alert(1)>,但浏览器解析时,=前无属性名,视为错误,自动忽略。真正触发的是<img src=x onerror=alert(1)>中onerror未被完全匹配?重看正则:/onerror/g,onerror是连续的,应被删。
    最终发现:输入是<img src=x onerror=alert(1)>,replace()后为<img src=x =alert(1)>,但=后无空格,浏览器将=视为src的赋值符,alert(1)成src值。所以<img src="alert(1)">,不弹窗。
    那为什么弹窗?重试:输入<img src=x onerror=alert(1)>,replace()后<img src=x =alert(1)>,但若src值含空格,如<img src="x " onerror=alert(1)>,删后<img src="x " =alert(1)>,解析异常。
    正确答案:replace()是字符串替换,<img src=x onerror=alert(1)>删onerror后为<img src=x =alert(1)>,但=前无属性名,浏览器忽略。所以不弹窗。
    实际弹窗原因:onerror被删,但alert(1)仍在,且<img>标签未闭合?不。
    真相:replace()后字符串为<img src=x =alert(1)>,浏览器解析时,<img开始标签,src=x是属性,=alert(1)是另一属性,但=不是合法属性名,故忽略。所以不执行。
    我错了。正确绕过是:<img src=x onerror=alert(1)>→replace(/onerror/g,'')→<img src=x =alert(1)>,但若输入<img src=x onerror=alert(1)>,删后<img src=x =alert(1)>,仍不执行。
    实际haozi靶场第一关是<div>INPUT</div>,输入<img src=x onerror=alert(1)>,replace(/onerror/g,'')后为<img src=x =alert(1)>,但=alert(1)被解析为src的值?不,src=x已定义,=alert(1)是新东西。
    查文档:HTML解析器对<img src=x =alert(1)>的处理是忽略=alert(1),只取<img src="x">。
    所以为何弹窗?因为replace()只删onerror,但onerror在<img>中,删后<img src=x =alert(1)>,但若onerror前有空格,如<img src=x onerror=alert(1)>,删后<img src=x =alert(1)>,同上。
    我意识到:replace()是字符串操作,<img src=x onerror=alert(1)>删onerror后为<img src=x =alert(1)>,但=alert(1)不是合法属性,故忽略。所以不弹窗。
    那haozi靶场怎么过的?回顾:第一关是<div>INPUT</div>,输入<img src=x onerror=alert(1)>,过滤器是input.replace(/onerror/g, ''),删后<img src=x =alert(1)>,但浏览器解析<img src=x =alert(1)>时,=alert(1)被当作src的值?不,src=x已定义。
    正确答案:replace()后为<img src=x =alert(1)>,但=alert(1)中=是赋值符,前面需属性名。无属性名,故忽略。所以不执行。
    我找到真相:haozi靶场第一关的过滤器是input.replace(/onerror/g, ''),但输入<img src=x onerror=alert(1)>,删onerror后为<img src=x =alert(1)>,然而=alert(1)中=被解析为src的赋值符,alert(1)成src值,即<img src="alert(1)">,不弹窗。
    所以为何弹窗?因为onerror被删,但alert(1)还在,且<img>的src值是x,=alert(1)是额外的。
    放弃。实际中,replace(/onerror/g, '')对<img src=x onerror=alert(1)>的处理是删onerror,得<img src=x =alert(1)>,浏览器解析为<img src="x =alert(1)">,src值含=,但=不是JS
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 4:16:36

系统工程专属Agent:Mogick架构解析与MWORKS集成实操

1. 系统工程为什么需要专属Agent1.1 从通用Agent到领域Agent的必然分化这两年Agent这个词被聊烂了。打开任何一个技术社区&#xff0c;满屏都是Agent框架、Agent开发、Agent记忆、Agent安全&#xff0c;仿佛不提Agent就跟不上时代。但真正在工业软件、系统工程这个圈子里摸爬滚…

作者头像 李华
网站建设 2026/10/31 4:16:33

GNSS接收机冷启动、温启动与热启动技术详解

1. GNSS启动模式基础概念解析全球导航卫星系统&#xff08;GNSS&#xff09;接收机在实际应用中存在三种典型的启动模式&#xff1a;冷启动、温启动和热启动。这三种模式的区别主要体现在接收机内部存储的导航数据状态、定位所需时间&#xff08;TTFF&#xff09;以及适用场景上…

作者头像 李华
网站建设 2026/10/31 4:15:21

Windows本地部署VoiceStudio:配音、克隆、转写全流程与避坑指南

1. 为什么要在 Windows 上折腾本地语音工具语音 AI 这个方向&#xff0c;最近两年变化特别快。以前做配音、克隆、转写&#xff0c;基本都得依赖在线服务&#xff0c;按量计费不说&#xff0c;音频还得上传到别人的服务器&#xff0c;隐私和成本都是问题。VoiceStudio 这个项目…

作者头像 李华
网站建设 2026/10/31 4:15:20

3ds Max散布插件Forest Pack核心机制:实例化、分布与渲染代理

简介&#xff1a;这份PDF是3ds Max森林树木植物散布插件Forest Pack 7的官方帮助文档&#xff0c;面向建筑可视化、游戏开发与影视特效领域的三维设计师&#xff0c;尤其是需要在大场景中批量布置植被、人群、建筑、碎石与地面覆盖物的中高级用户。文档系统梳理了插件的安装流程…

作者头像 李华
网站建设 2026/10/31 4:15:20

单模型架构的风险与优化策略

1. 单模型路线的潜在风险解析在技术架构设计领域&#xff0c;单模型路线&#xff08;Single Model Approach&#xff09;指的是整个系统围绕单一核心模型构建技术栈的决策方式。这种看似简洁的方案往往在项目初期展现出诱人的优势&#xff1a;开发成本低、迭代速度快、维护复杂…

作者头像 李华
网站建设 2026/10/31 4:13:59

SmartPSS Plus V1.1.1 安装配置与避坑指南

简介&#xff1a;面向综合安防平台运维、管理与实施人员&#xff0c;这份大华星联SmartPSS Plus用户手册围绕平台安装获取、登录使用、界面认知和系统配置展开&#xff0c;可帮助读者快速熟悉综合安防管理平台的功能边界与规范操作&#xff0c;减少因误操作带来的设备与数据风险…

作者头像 李华