您现在的位置是:网站首页 > DOM 型 XSS文章详情

DOM 型 XSS

DOM 型 XSS 的基本概念

DOM 型 XSS 是一种特殊类型的跨站脚本攻击,其恶意代码的执行完全发生在客户端,不经过服务器端处理。与反射型或存储型 XSS 不同,DOM 型 XSS 的漏洞根源在于客户端 JavaScript 对不可信数据的处理方式。攻击者通过操纵 DOM 环境,诱使受害者的浏览器执行恶意脚本。

典型的 DOM 型 XSS 攻击流程:

  1. 用户访问包含漏洞的网页
  2. 浏览器创建页面的 DOM 表示
  3. 恶意数据被插入到 DOM 中
  4. 浏览器解析并执行插入的恶意代码

DOM 型 XSS 的工作原理

DOM 型 XSS 的核心在于 JavaScript 对 document.locationdocument.URLdocument.referrer 等客户端对象的处理。当这些值被直接用于动态生成 DOM 内容而没有适当过滤时,就可能产生漏洞。

// 危险的示例
const userInput = document.location.hash.substring(1);
document.getElementById('output').innerHTML = userInput;

在这个例子中,攻击者可以构造如下 URL:

http://example.com/page.html#<script>alert('XSS')</script>

当用户访问这个 URL 时,恶意脚本就会被执行。

常见的 DOM XSS 触发点

1. 基于 URL 的注入

URL 参数是最常见的攻击向量:

// 从URL获取参数的不安全方式
const searchParams = new URLSearchParams(window.location.search);
const name = searchParams.get('name');
document.write(`Hello ${name}`);

攻击者可以构造恶意链接:

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

2. HTML5 localStorage/sessionStorage

// 不安全的storage使用
const userPref = localStorage.getItem('user-preference');
document.body.innerHTML = userPref;

3. 第三方脚本操作

// 不安全的第三方脚本集成
const script = document.createElement('script');
script.src = untrustedSource;
document.body.appendChild(script);

高级 DOM XSS 技术

1. 基于 DOM clobbering 的攻击

<!-- 恶意HTML注入 -->
<form id="document" action="javascript:alert('XSS')"></form>
<a id="URL" href="javascript:alert('XSS')"></a>

2. 原型链污染

// 原型污染示例
const maliciousPayload = '{"__proto__":{"isAdmin":true}}';
JSON.parse(maliciousPayload);

// 之后在代码中
if (user.isAdmin) {
  // 授予管理员权限
}

防御 DOM 型 XSS 的策略

1. 安全的 DOM 操作方法

// 使用textContent代替innerHTML
const userInput = document.location.hash.substring(1);
document.getElementById('output').textContent = userInput;

// 使用createElement和appendChild
const div = document.createElement('div');
div.textContent = userInput;
document.body.appendChild(div);

2. 内容安全策略 (CSP)

<!-- 严格的CSP策略 -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'unsafe-inline'">

3. 输入验证和清理

// 使用DOMPurify清理HTML
const clean = DOMPurify.sanitize(dirtyInput);
document.getElementById('output').innerHTML = clean;

// 自定义验证函数
function sanitizeInput(input) {
  return input.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

现代框架中的 DOM XSS 防护

1. React 的安全特性

// React默认会转义内容
const userInput = window.location.hash.substring(1);
return <div>{userInput}</div>; // 自动转义

// 危险地设置innerHTML
<div dangerouslySetInnerHTML={{__html: userInput}} />; // 需要显式确认

2. Vue 的防护机制

<template>
  <!-- 自动转义 -->
  <div>{{ userInput }}</div>
  
  <!-- 显式原始HTML -->
  <div v-html="userInput"></div>
</template>

3. Angular 的安全上下文

// Angular的安全处理
import { DomSanitizer } from '@angular/platform-browser';

constructor(private sanitizer: DomSanitizer) {}

safeHtml = this.sanitizer.bypassSecurityTrustHtml(untrustedHtml);

自动化检测工具

1. 静态分析工具

  • ESLint 插件:eslint-plugin-security
  • 自定义规则示例:
{
  "rules": {
    "security/detect-unsafe-regex": "error",
    "security/detect-eval-with-expression": "error"
  }
}

2. 动态测试工具

  • OWASP ZAP
  • Burp Suite DOM Invader
  • 浏览器扩展:DOM XSS Scanner

3. 单元测试中的检测

// 使用Jest测试XSS漏洞
test('should sanitize user input', () => {
  const maliciousInput = '<script>alert(1)</script>';
  const safeOutput = sanitizeInput(maliciousInput);
  expect(safeOutput).not.toContain('<script>');
});

实际案例分析

1. 基于 hashchange 的事件攻击

// 不安全的hashchange处理
window.addEventListener('hashchange', function() {
  document.getElementById('content').innerHTML = location.hash.slice(1);
});

// 攻击者可以构造:
// http://example.com/#<img src=x onerror=alert(document.cookie)>

2. JSONP 回调漏洞

// 不安全的JSONP实现
function handleResponse(data) {
  document.write('User: ' + data.username);
}

const script = document.createElement('script');
script.src = 'https://api.example.com/user?callback=handleResponse';
document.body.appendChild(script);

// 攻击者可以注入恶意回调
https://api.example.com/user?callback=alert(1)//

3. 动态样式表注入

// 不安全的样式表处理
const userTheme = localStorage.getItem('theme');
const style = document.createElement('style');
style.innerHTML = userTheme;
document.head.appendChild(style);

// 攻击者可以注入:
// background: url('javascript:alert(1)');

浏览器安全机制与绕过

1. XSS Auditor 的局限性

虽然现代浏览器有内置的XSS防护,但DOM型XSS经常能绕过:

// 绕过XSS Auditor的技巧
const payload = 'javascript:alert(1)'.split('').reverse().join('');
document.location = payload;

2. Trusted Types API

现代浏览器的防护机制:

// 启用Trusted Types
if (window.trustedTypes && window.trustedTypes.createPolicy) {
  const escapePolicy = trustedTypes.createPolicy('escapePolicy', {
    createHTML: str => str.replace(/</g, '&lt;').replace(/>/g, '&gt;')
  });
}

// 使用策略
element.innerHTML = escapePolicy.createHTML(untrustedInput);

3. 同源策略的边界情况

// 跨源窗口引用
const win = window.open('https://attacker.com');
setTimeout(() => {
  win.location = 'javascript:alert(document.domain)';
}, 1000);

开发流程中的安全实践

1. 安全代码审查清单

  • [ ] 是否避免使用 innerHTML/outerHTML
  • [ ] 所有动态内容是否经过适当转义?
  • [ ] 是否限制了 eval()setTimeout(string) 等危险函数?
  • [ ] CSP 策略是否适当配置?

2. 安全编码规范示例

// 安全的数据绑定模式
function safeTemplate(strings, ...values) {
  let result = strings[0];
  for (let i = 0; i < values.length; i++) {
    result += escapeHtml(values[i]) + strings[i + 1];
  }
  return result;
}

function escapeHtml(str) {
  return str.toString()
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');
}

3. 持续集成中的安全检查

# .github/workflows/security.yml
name: Security Checks
on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - run: npm install
      - run: npm run lint-security
      - run: npm run test-xss

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步