DOM-based XSS
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:
-
Sources: User-controllable input points
document.URL
document.location
document.referrer
window.name
localStorage/sessionStorage
- Data received via
postMessage
-
Propagation: Insecure API usage
innerHTML/outerHTML
document.write/document.writeln
- Dynamic execution via
eval/setTimeout/setInterval
location.href/location.assign
-
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
-
Static Analysis Tools:
- ESLint plugin: eslint-plugin-security
- Semgrep rule sets
-
Dynamic Detection Tools:
- OWASP ZAP
- Burp Suite DOM Invader
- Chrome DevTools XSS auditing features
-
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:
- Server-side sanitization
- Iframe sandbox isolation
- Strict CSP policies
- Plain text preview options
Browser Security Mechanisms
- Trusted Types API:
// Enable Trusted Types
if (window.trustedTypes && trustedTypes.createPolicy) {
const escapePolicy = trustedTypes.createPolicy("escapePolicy", {
createHTML: (str) => str.replace(/</g, "<")
});
}
- XSS Auditor (deprecated):
- Chrome's former protection against reflected XSS
- Replaced by CSP
- 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 = {
"<": "<",
">": ">",
// ...other characters needing escaping
};
function fastEscape(str) {
return String(str).replace(/[<>]/g, (m) => escapeMap[m]);
}
Related Vulnerability Patterns
- 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>
- XSS in jQuery:
// Insecure jQuery usage
$("#container").html(userControlledInput);
// Secure usage
$("#container").text(userControlledInput);
- 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
上一篇:存储型 XSS(持久型)
下一篇:XSS 攻击的危害与影响