阿里云主机折上折
  • 微信号
Current Site:Index > DOM-based XSS

DOM-based XSS

Author:Chuan Chen 阅读数:10709人阅读 分类: 前端安全

Basic Concepts of DOM-based XSS

DOM-based XSS is a special type of cross-site scripting attack where the execution of malicious code occurs entirely within the client-side DOM environment, without involving server-side processing. Unlike reflected or stored XSS, the root cause of DOM-based XSS lies in the insecure handling of user input by frontend JavaScript code.

// Typical vulnerability example
const userInput = window.location.hash.substring(1);
document.getElementById("output").innerHTML = userInput;

In this example, an attacker can construct a URL like #<img src=x onerror=alert(1)>. When a user visits this URL, arbitrary JavaScript code will be executed.

Vulnerability Generation Principles

DOM-based XSS typically involves the following key stages:

  1. Sources: User-controllable input points

    • document.URL
    • document.location
    • document.referrer
    • window.name
    • localStorage/sessionStorage
    • Data received via postMessage
  2. Propagation: Insecure API usage

    • innerHTML/outerHTML
    • document.write/document.writeln
    • Dynamic execution via eval/setTimeout/setInterval
    • location.href/location.assign
  3. Sinks: Contexts where code execution is ultimately triggered

    • HTML parsing context
    • JavaScript execution context
    • URL context

Analysis of Common Dangerous Scenarios

Dynamic Content Insertion

// Dangerous example: Direct insertion of unescaped content
function showSearchResults(query) {
  const results = searchDatabase(query);
  document.getElementById("results").innerHTML = 
    `<div>Search results for "${query}":</div>`;
}

An attacker can submit a query parameter like "><script>alert(1)</script> to inject a script.

URL-based XSS

// Retrieving parameters from URL fragments
const token = window.location.hash.slice(1);
document.write(`<input type="hidden" value="${token}">`);

If the URL contains #"><script>alert(1)</script>, an XSS vulnerability will be triggered.

JSONP Callback Vulnerability

function handleResponse(data) {
  document.getElementById("user-data").innerHTML = data.userInfo;
}

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

If the API returns {"userInfo": "<img src=x onerror=alert(1)>"}, XSS will be triggered.

DOM XSS in Modern Frontend Frameworks

Even modern frameworks like React and Vue can pose DOM XSS risks if used improperly:

Risks in React

// Dangerous usage
function UserProfile({ userInput }) {
  return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
}

Vue's v-html

<!-- Potential XSS risk -->
<template>
  <div v-html="userProvidedContent"></div>
</template>

Angular's bypassSecurityTrust

// Insecure usage
constructor(private sanitizer: DomSanitizer) {}
displayContent() {
  this.trustedContent = this.sanitizer.bypassSecurityTrustHtml(userInput);
}

Defense Strategies and Techniques

Input Validation and Sanitization

// Sanitizing HTML using DOMPurify
import DOMPurify from "dompurify";

const clean = DOMPurify.sanitize(dirtyInput, {
  ALLOWED_TAGS: ["b", "i", "em", "strong"],
  ALLOWED_ATTR: ["style"]
});

Safe DOM Manipulation Methods

// Using textContent instead of innerHTML
element.textContent = userInput;

// Creating elements using DOM API
const div = document.createElement("div");
div.appendChild(document.createTextNode(userInput));

Content Security Policy (CSP)

<!-- Strict CSP policy -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'unsafe-inline'">

Best Practices in Modern Frameworks

React example:

// Safe usage
function SafeComponent({ text }) {
  return <div>{text}</div>;
}

Vue example:

<!-- Safe content binding -->
<template>
  <div>{{ userContent }}</div>
</template>

Advanced Attack Techniques and Defenses

Prototype Pollution-based XSS

// Attackers can pollute the prototype chain to cause XSS
Object.prototype.innerHTML = "<script>alert(1)</script>";
document.body.appendChild(document.createElement("div"));

Defense methods:

// Freeze Object.prototype
Object.freeze(Object.prototype);

// Check with hasOwnProperty
if (element.hasOwnProperty("innerHTML")) {
  element.innerHTML = safeContent;
}

XSS in SVG Files

<!-- Malicious SVG file example -->
<svg xmlns="http://www.w3.org/2000/svg">
  <script>alert(1)</script>
</svg>

Defense strategies:

  • Set correct Content-Type on the server
  • Use specialized SVG sanitization libraries
  • Avoid directly rendering user-uploaded SVGs

XSS in Web Workers

// XSS risks can also exist in Workers
const workerCode = `onmessage=function(e){eval(e.data)}`;
const blob = new Blob([workerCode]);
const worker = new Worker(URL.createObjectURL(blob));
worker.postMessage("alert(1)");

Safe approach:

// Use structured cloning algorithm to pass data
worker.postMessage({ command: "render", data: sanitizedHTML });

Automated Detection Tools

  1. Static Analysis Tools:

    • ESLint plugin: eslint-plugin-security
    • Semgrep rule sets
  2. Dynamic Detection Tools:

    • OWASP ZAP
    • Burp Suite DOM Invader
    • Chrome DevTools XSS auditing features
  3. Unit Testing Solutions:

// Testing XSS protection with Jest
test("sanitize function prevents XSS", () => {
  const malicious = "<script>alert(1)</script>";
  expect(sanitize(malicious)).not.toContain("<script>");
});

Real-world Case Studies

Case 1: Single-Page Application Routing XSS

// Insecure implementation
router.beforeEach((to, from, next) => {
  document.title = to.query.title || "Default Title";
  next();
});

An attacker can construct a URL like ?title=<script>alert(1)</script>.

Fix:

// Secure implementation
router.beforeEach((to, from, next) => {
  document.title = sanitizeTitle(to.query.title) || "Default Title";
  next();
});

function sanitizeTitle(str) {
  return String(str).replace(/[<>]/g, "");
}

Case 2: Rich Text Editor Vulnerability

// Insecure rich text handling
editor.on("save", (content) => {
  saveToDatabase(content);
  preview.innerHTML = content;
});

Defense measures should include:

  1. Server-side sanitization
  2. Iframe sandbox isolation
  3. Strict CSP policies
  4. Plain text preview options

Browser Security Mechanisms

  1. Trusted Types API:
// Enable Trusted Types
if (window.trustedTypes && trustedTypes.createPolicy) {
  const escapePolicy = trustedTypes.createPolicy("escapePolicy", {
    createHTML: (str) => str.replace(/</g, "&lt;")
  });
}
  1. XSS Auditor (deprecated):
  • Chrome's former protection against reflected XSS
  • Replaced by CSP
  1. Cross-Origin Isolation:
// Enable cross-origin isolation
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Balancing Performance and Security

// Secure but slow approach
function safeButSlow(content) {
  const temp = document.createElement("div");
  temp.textContent = content;
  return temp.innerHTML;
}

// Balanced solution
const escapeMap = {
  "<": "&lt;",
  ">": "&gt;",
  // ...other characters needing escaping
};

function fastEscape(str) {
  return String(str).replace(/[<>]/g, (m) => escapeMap[m]);
}

Related Vulnerability Patterns

  1. DOM Clobbering:
<!-- Polluting global variables via DOM -->
<form id="xss"><input name="innerHTML" value="<script>alert(1)</script>"></form>
<script>
  // xss.innerHTML has been polluted
  document.body.appendChild(xss);
</script>
  1. XSS in jQuery:
// Insecure jQuery usage
$("#container").html(userControlledInput);

// Secure usage
$("#container").text(userControlledInput);
  1. Dynamic Script Loading:
// Insecure dynamic script loading
const script = document.createElement("script");
script.src = untrustedURL;
document.body.appendChild(script);

Secure alternative:

// Use import() for dynamic loading
import(/* webpackIgnore: true */ trustedURL)
  .catch(() => { /* Error handling */ });

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.