Understanding DOM-Based Attacks
DOM-based attacks target vulnerabilities in client-side JavaScript code that improperly handles user input when modifying the Document Object Model (DOM). These attacks execute entirely in the browser, unlike traditional server-side exploits, making them harder to detect and prevent. Attackers exploit insecure data flows from sources (user-controlled input) to sinks (dangerous DOM manipulation functions) to execute malicious actions like redirection, data theft, or script injection.
Key Concepts
Core Components
- Source: Entry points for untrusted data (e.g.,
location.hash,document.URL,document.referrer). - Sink: Dangerous JavaScript functions or properties (e.g.,
eval(),innerHTML,location). - Vulnerability: Occurs when data flows from a source to a sink without proper validation or sanitization.
Critical Insight: DOM-based attacks bypass server-side security controls, relying solely on client-side execution.
Common Attack Vectors
DOM-Based Open Redirection
Exploits URL fragments (after #) to manipulate navigation. Attackers craft malicious URLs that pass weak validation checks, redirecting users to phishing or malware sites.
Vulnerable Code Example
goto = location.hash.slice(1);
if (goto.startsWith('https:')) {
location = goto;
}
Vulnerability Analysis
| Component | Value | Issue |
|---|---|---|
| Source | location.hash.slice(1) | Extracts user-controlled URL fragment |
| Sink | location = goto | Direct assignment without sanitization |
| Validation | goto.startsWith('https:') | Insufficient (only checks protocol) |
Exploitation Flow
- Attacker crafts a URL:
https://realwebsite.com/#https://attacker.com - JavaScript extracts
https://attacker.comfrom the hash. - Weak validation passes (starts with
https:). - Browser redirects to the attacker’s domain.
- User perceives the redirect as legitimate.
Mitigation Strategies
Input Validation
- Whitelist allowed domains instead of protocol checks.
- Use the
URLAPI to parse and validate destinations. - Reject malformed or unexpected input.
Secure Code Example
const allowedDomains = ['realwebsite.com', 'trusted-partner.com'];
const goto = location.hash.slice(1);
try {
const url = new URL(goto);
if (allowedDomains.includes(url.hostname)) {
location = goto;
}
} catch (e) {
console.error('Invalid redirect URL');
}
Safe Coding Practices
- Avoid dangerous sinks: Replace
eval(),innerHTML, and directlocationassignments with safer alternatives.- Use
textContentinstead ofinnerHTML. - Use
setAttribute()for DOM modifications.
- Use
- Encode output: Always encode data before inserting into the DOM (e.g.,
encodeURIComponent()). - Content Security Policy (CSP): Restrict inline scripts and external resources with headers like:
Content-Security-Policy: script-src 'self'; object-src 'none';
Security Audits
- Code reviews: Trace data flows from sources to sinks.
- Static analysis tools: Use tools like ESLint (with security plugins) or SonarQube.
- Penetration testing: Simulate attacks to identify weaknesses.
- Third-party libraries: Monitor advisories for vulnerabilities in dependencies.
Prevention Checklist
- Validate all user-controlled input (sources) before use.
- Replace dangerous sinks with secure alternatives.
- Implement CSP headers to restrict script execution.
- Encode dynamic content before DOM insertion.
- Conduct regular security audits and testing.
Learn More
- OWASP DOM-Based XSS Prevention Cheat Sheet: owasp.org/www-project-cheatsheets
- PortSwigger Web Security Academy: Interactive labs for DOM-based attacks (portswigger.net/web-security).
- MDN Web Security: Best practices for secure JavaScript (developer.mozilla.org/en-US/docs/Web/Security).
- Browser Developer Tools: Use the console to trace data flows and debug sources/sinks.