← Tilbage til security guides

Cross-Site Scripting Prevention

Cross-Site Scripting (XSS) er en sårbarhed hvor angribere kan injicere ondsindet JavaScript i websider der vises til andre brugere.

⚠️High Severity
⚠️

Om Truslen

Cross-Site Scripting (XSS) er en af de mest udbredte sikkerhedssårbarheder på nettet og optræder konsekvent i OWASP Top 10. XSS opstår når en applikation inkluderer uvalideret eller uescaped brugerinput i output sendt til browseren. Dette giver angribere mulighed for at udføre JavaScript i offerets browser-kontekst, hvilket kan resultere i session hijacking, cookie theft, defacement, phishing-angreb og malware distribution. Statistikker viser at cirka 40% af alle cyberangreb involverer XSS i en eller anden form. XSS er særligt farligt fordi det kan bruges til at omgå Same-Origin Policy og få fuld adgang til alt indhold på siden, inklusive følsomme data. Der findes tre hovedtyper: Reflected XSS (ikke-persistent), Stored XSS (persistent) og DOM-based XSS, hver med deres egne karakteristika og udfordringer.

Key Points

  • Escape ALT output før det sendes til browseren - antag at alt input er ondsindet
  • Brug htmlspecialchars() eller htmlentities() med ENT_QUOTES flag for HTML-kontekst
  • Implementer Content Security Policy (CSP) headers for at begrænse script-eksekveringer
  • Brug HTTP-only og Secure flags på cookies for at forhindre JavaScript-adgang
  • Validér og sanitér input på server-side - client-side validering er ikke nok
  • Brug template engines med automatisk escaping (Twig, Blade)
  • Undgå at bruge eval(), innerHTML eller document.write() med brugerinput
  • Implementer X-XSS-Protection header (selvom moderne browsere har bedre beskyttelse)
  • Brug contextual output encoding baseret på hvor data vises (HTML, JavaScript, CSS, URL)
  • Implementér strict input validation med whitelists hvor muligt
  • Brug X-Content-Type-Options: nosniff header for at forhindre MIME-sniffing
  • Sanitér rich text editors med biblioteker som HTML Purifier
  • Implementér CSP nonce eller hash-baseret script whitelisting
  • Opdater regelmæssigt JavaScript libraries for at undgå kendte XSS-sårbarheder

Sårbar Kode (UNDGÅ)

Brug ALDRIG denne kode i produktion!

<?php
// SÅRBAR KODE - Brug ALDRIG dette i produktion!

// 1. Reflected XSS - Direkte echo af brugerinput
$name = $_GET['name'];
echo "<h1>Welcome, " . $name . "!</h1>";
// URL: page.php?name=<script>alert('XSS')</script>
// Dette vil eksekevere scriptet i brugerens browser

// 2. Stored XSS - Gemmer ondsindet input i database
$comment = $_POST['comment'];
$query = "INSERT INTO comments (text) VALUES ('$comment')";
mysqli_query($conn, $query);

// Senere når kommentarer vises:
$result = mysqli_query($conn, "SELECT text FROM comments");
while ($row = mysqli_fetch_assoc($result)) {
    echo "<p>" . $row['text'] . "</p>";
    // Hvis comment indeholder <script>steal_cookies()</script>
    // vil det køre hver gang nogen ser kommentaren!
}

// 3. XSS i HTML-attributter
$search = $_GET['q'];
echo "<input type='text' value='" . $search . "'>";
// URL: page.php?q=' onload='alert(document.cookie)
// Resulterer i: <input type='text' value='' onload='alert(document.cookie)'>

// 4. XSS i JavaScript-kontekst
$user_data = $_GET['data'];
echo "<script>var userData = '" . $user_data . "';</script>";
// URL: page.php?data='; alert('XSS'); //
// Resulterer i: var userData = ''; alert('XSS'); //';

// 5. DOM-based XSS via PHP
$callback = $_GET['callback'];
echo "<script>" . $callback . "(data);</script>";
// URL: page.php?callback=maliciousFunction

// 6. XSS i href-attribut
$url = $_GET['url'];
echo "<a href='" . $url . "'>Click here</a>";
// URL: page.php?url=javascript:alert('XSS')
// eller: page.php?url=data:text/html,<script>alert('XSS')</script>

// 7. XSS gennem CSS
$color = $_GET['color'];
echo "<div style='color: " . $color . "'>Text</div>";
// URL: page.php?color=red; background: url(javascript:alert('XSS'))

// 8. Usikker JSON output
header('Content-Type: application/json');
echo json_encode(['message' => $_POST['message']]);
// Hvis Content-Type ikke sættes korrekt eller browseren gætter forkert
?>

Sikker Kode (ANBEFALET)

Best practices for sikker implementation

<?php
// SIKKER KODE - Best practices for XSS prevention

// 1. Korrekt output escaping med htmlspecialchars()
$name = $_GET['name'] ?? 'Guest';
// ENT_QUOTES escaper både enkelt- og dobbelt-quotes
// ENT_HTML5 understøtter HTML5
echo "<h1>Welcome, " . htmlspecialchars($name, ENT_QUOTES | ENT_HTML5, 'UTF-8') . "!</h1>";

// 2. Stored XSS prevention med sanitering og escaping
$comment = $_POST['comment'] ?? '';

// Validér længde
if (strlen($comment) > 1000) {
    die("Comment too long");
}

// Brug prepared statement til at gemme (forhindrer også SQL injection)
$stmt = $pdo->prepare("INSERT INTO comments (text, created_at) VALUES (?, NOW())");
$stmt->execute([$comment]);

// Når data vises: ALTID escape output
$stmt = $pdo->query("SELECT text, created_at FROM comments");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo "<p>" . htmlspecialchars($row['text'], ENT_QUOTES, 'UTF-8') . "</p>";
    echo "<small>" . htmlspecialchars($row['created_at'], ENT_QUOTES, 'UTF-8') . "</small>";
}

// 3. Sikker håndtering af HTML-attributter
$search = $_GET['q'] ?? '';
echo "<input type='text' value='" . htmlspecialchars($search, ENT_QUOTES, 'UTF-8') . "'>";

// 4. Sikker JavaScript-variabel
$user_data = $_GET['data'] ?? '';
// Brug json_encode() for at escape JavaScript-kontekst korrekt
echo "<script>var userData = " . json_encode($user_data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . ";</script>";

// 5. URL validation og sanitering
$url = $_GET['url'] ?? '';

// Whitelist tilladte protocols
$allowed_protocols = ['http', 'https'];
$parsed_url = parse_url($url);

if (isset($parsed_url['scheme']) && in_array($parsed_url['scheme'], $allowed_protocols, true)) {
    echo "<a href='" . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . "'>Click here</a>";
} else {
    echo "<a href='#'>Invalid URL</a>";
}

// 6. Rich text med HTML Purifier
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);

$dirty_html = $_POST['content'] ?? '';
$clean_html = $purifier->purify($dirty_html);
echo $clean_html; // Sikkert at outputte

// 7. Content Security Policy header
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-" . base64_encode(random_bytes(16)) . "'; object-src 'none'; base-uri 'self';");

// 8. Sikre cookie settings
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');

// 9. Security headers
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
?>

Almindelige Fejl

  • At glemme at escape output i templates og tro at input-validering er nok
  • At bruge strip_tags() som primær beskyttelse - dette kan omgås og fjerner ikke alle XSS-vektorer
  • At escape output kun i HTML-kontekst, men glemme JavaScript, CSS og URL-kontekster
  • At stole på client-side validering eller filtering - alt skal valideres på server-side
  • At tro at htmlentities() uden ENT_QUOTES flag beskytter mod XSS i attributter
  • At implementere hjemmelavede sanitizing-funktioner i stedet for at bruge etablerede biblioteker som HTML Purifier

Forebyggelsesteknikker

  • 🛡️Brug context-aware output encoding: htmlspecialchars() for HTML, json_encode() for JavaScript
  • 🛡️Implementér Content Security Policy (CSP) headers med strict-dynamic og nonces
  • 🛡️Brug template engines med auto-escaping som Twig eller Blade
  • 🛡️Implementér HTTP-only, Secure og SameSite flags på alle cookies
  • 🛡️Brug HTML Purifier eller lignende biblioteker for rich text content
  • 🛡️Implementér input validation med whitelists på server-side
  • 🛡️Brug Trusted Types API i moderne browsere for DOM-manipulation
  • 🛡️Implementér security headers: X-Content-Type-Options, X-Frame-Options

Testing Metoder

  • 🔍Manuel testing med XSS payloads i alle input-felter: <script>alert(1)</script>, \"'><script>alert(1)</script>
  • 🔍Automated scanning med værktøjer som Burp Suite, OWASP ZAP eller XSSer
  • 🔍DOM-based XSS testing med DOM Invader eller manual JavaScript analyse
  • 🔍Code review med fokus på alle echo, print og template output statements
  • 🔍Brug af browser extensions som XSS Hunter til at finde blind XSS

Quick Info

Severity Level
⚠️High
Relaterede Trusler
  • Content Injection - Injection af ondsindet indhold uden script-eksekvetion
  • HTML Injection - Manipulation af HTML-struktur
  • CSRF - Cross-Site Request Forgery som ofte kombineres med XSS

⚠️Sikkerhedsadvarsel

Sikkerhedssårbarheder kan have alvorlige konsekvenser. Test altid grundigt i et sikkert miljø og implementer alle anbefalede forebyggelsesteknikker.