Unsachgemäße Kodierung oder Escaping von Ausgaben

Beschreibung

Unsachgemäße Kodierung oder Escaping von Ausgaben tritt auf, wenn Software eine strukturierte Nachricht zur Kommunikation mit einer anderen Komponente vorbereitet, die Daten jedoch nicht ordnungsgemäß kodiert oder escaped, wodurch Angreifer die Struktur der Nachricht verändern können. Dies ist die Grundursache vieler Injection-Schwachstellen. Die erforderliche spezifische Kodierung hängt vom Ausgabekontext ab: HTML-Kodierung für Webseiten, SQL-Escaping für Datenbankabfragen, Shell-Escaping für Befehlsausführung, URL-Kodierung für URLs und LDAP-Kodierung für Verzeichnisabfragen. Die Verwendung einer falschen oder fehlenden Kodierung ermöglicht Injection-Angriffe.

Risiko

Unsachgemäße Ausgabekodierung ist grundlegend für Injection-Schwachstellen in allen Kontexten. Cross-Site Scripting (XSS) resultiert aus unsachgemäßer HTML/JavaScript-Kodierung. SQL Injection entsteht durch unsachgemäße SQL-Kodierung. Command Injection ergibt sich aus unsachgemäßem Shell-Escaping. Jeder Kontext erfordert seine spezifische Kodierung, und die Verwendung des falschen Typs bietet keinen Schutz. Moderne Frameworks bieten automatische Kodierung, aber Entwickler müssen verstehen, welche Kontexte geschützt sind und welche manuelle Kodierung erfordern.

Lösung

Verwenden Sie kontextgerechte Kodierung für alle Ausgaben. Für den HTML-Kontext kodieren Sie HTML-Sonderzeichen (<, >, &, ", '). Für den JavaScript-Kontext verwenden Sie JavaScript-Kodierung. Für URL-Parameter verwenden Sie URL-Kodierung. Für SQL verwenden Sie parametrisierte Abfragen (keine Kodierung). Für Shell-Befehle verwenden Sie parametrisierte APIs oder korrektes Shell-Escaping. Verwenden Sie Template-Engines mit aktiviertem Auto-Escaping. Implementieren Sie Content Security Policy als Defense-in-Depth. Vertrauen Sie niemals darauf, dass Eingabevalidierung allein ausreicht -- kodieren Sie immer die Ausgabe.

Häufige Auswirkungen

AuswirkungDetails
IntegritätBereich: Nachrichtenmanipulation

Angreifer können die Struktur von Nachrichten, Abfragen oder Befehlen verändern.
VertraulichkeitBereich: Datendiebstahl

Durch unsachgemäße Kodierung ermöglichte Injection-Angriffe können sensible Daten extrahieren.
ZugriffskontrolleBereich: Code-Ausführung

In vielen Kontexten führt unsachgemäße Kodierung zu beliebiger Code-Ausführung.

Beispielcode und Lösung

Verwundbarer Code

# VERWUNDBAR: Keine HTML-Kodierung - XSS
@app.route('/search')
def search():
    query = request.args.get('q')
    # Benutzereingabe direkt in HTML - XSS!
    return f"<h1>Search results for: {query}</h1>"

# VERWUNDBAR: Falsche Kodierung für den Kontext
@app.route('/profile')
def profile():
    name = html.escape(request.args.get('name'))
    # HTML-escaped, aber im JavaScript-Kontext - immer noch verwundbar!
    return f"""
    <script>
        var username = "{name}";  // XSS via: " + alert(1) + "
    </script>
    """

# VERWUNDBAR: Keine URL-Kodierung
def create_redirect(url):
    # Angreifer kann einschleusen: javascript:alert(1)
    return f'<a href="{url}">Click here</a>'
// VERWUNDBAR: Direkte String-Verkettung in der Antwort
@GetMapping("/greet")
public void greet(@RequestParam String name, HttpServletResponse response)
        throws IOException {
    // Keine Kodierung - XSS-Schwachstelle
    response.getWriter().write("<h1>Hello " + name + "</h1>");
}

// VERWUNDBAR: LDAP Injection durch unsachgemäße Kodierung
public List<User> searchUsers(String username) {
    String filter = "(uid=" + username + ")";  // Keine LDAP-Kodierung!
    return ldapTemplate.search(baseDn, filter, new UserMapper());
}
// VERWUNDBAR: innerHTML mit Benutzerinhalten
function displayMessage(message) {
    // Direkte HTML-Injection
    document.getElementById('output').innerHTML = message;
}

// VERWUNDBAR: Falscher Kontext - HTML-kodiert aber in href
function createLink(url) {
    const escaped = escapeHtml(url);  // HTML-Kodierung
    // Aber javascript:-URLs umgehen die HTML-Kodierung!
    return `<a href="${escaped}">Link</a>`;
}

Sichere Lösung

# SICHER: Korrekte HTML-Kodierung
from markupsafe import escape
from flask import render_template

@app.route('/search')
def search_safe():
    query = request.args.get('q', '')
    # Template mit Auto-Escaping verwenden
    return render_template('search.html', query=query)

# Oder manuelles Escaping:
@app.route('/search')
def search_safe_manual():
    query = escape(request.args.get('q', ''))
    return f"<h1>Search results for: {query}</h1>"

# SICHER: Korrekte Kodierung für JavaScript-Kontext
import json

@app.route('/profile')
def profile_safe():
    name = request.args.get('name', '')
    # JSON-Kodierung für JavaScript-Kontext
    safe_name = json.dumps(name)  # Korrekt escaped für JS
    return f"""
    <script>
        var username = {safe_name};
    </script>
    """

# SICHER: URL-Validierung und -Kodierung
from urllib.parse import quote, urlparse

def create_redirect_safe(url):
    parsed = urlparse(url)
    # Nur http/https-Schemata erlauben
    if parsed.scheme not in ('http', 'https', ''):
        raise ValueError("Invalid URL scheme")

    # URL-Kodierung und HTML-Kodierung
    safe_url = escape(url)
    return f'<a href="{safe_url}">Click here</a>'
// SICHER: Verwendung von Response-Kodierung
@GetMapping("/greet")
public void greetSafe(@RequestParam String name, HttpServletResponse response)
        throws IOException {
    response.setContentType("text/html; charset=UTF-8");
    String safeName = HtmlUtils.htmlEscape(name);
    response.getWriter().write("<h1>Hello " + safeName + "</h1>");
}

// Besser: Template-Engine mit Auto-Escaping verwenden
@GetMapping("/greet")
public String greetTemplate(@RequestParam String name, Model model) {
    model.addAttribute("name", name);  // Thymeleaf escaped automatisch
    return "greet";  // greet.html Template
}

// SICHER: LDAP-Kodierung
import org.springframework.ldap.support.LdapEncoder;

public List<User> searchUsersSafe(String username) {
    String safeUsername = LdapEncoder.filterEncode(username);
    String filter = "(uid=" + safeUsername + ")";
    return ldapTemplate.search(baseDn, filter, new UserMapper());
}
// SICHER: textContent statt innerHTML verwenden
function displayMessageSafe(message) {
    // textContent ist automatisch sicher - kein HTML-Parsing
    document.getElementById('output').textContent = message;
}

// SICHER: Korrekte URL-Validierung für href
function createLinkSafe(url) {
    try {
        const parsed = new URL(url, window.location.origin);
        // Nur http/https erlauben
        if (!['http:', 'https:'].includes(parsed.protocol)) {
            throw new Error('Invalid protocol');
        }
        const a = document.createElement('a');
        a.href = parsed.href;  // Browser übernimmt die Kodierung
        a.textContent = 'Link';
        return a.outerHTML;
    } catch (e) {
        return '<span>Invalid URL</span>';
    }
}

// SICHER: Kontextbewusste Kodierungsbibliothek
const he = require('he');  // HTML-Entities-Bibliothek

function encodeForHtmlAttribute(str) {
    return he.encode(str, { useNamedReferences: true });
}

function encodeForJavaScript(str) {
    return JSON.stringify(str);
}

function encodeForUrl(str) {
    return encodeURIComponent(str);
}

Ausgenutzt in der Praxis

Cross-Site Scripting (XSS)-Angriffe (fortlaufend)

Unsachgemäße HTML-Kodierung ist die Grundursache für Stored- und Reflected-XSS-Schwachstellen, die praktisch jede größere Webanwendung irgendwann betroffen haben.

LDAP-Injection-Angriffe

Unsachgemäße LDAP-Kodierung hat zu Authentifizierungs-Umgehung und Datenextraktion in Enterprise-Verzeichnisdiensten geführt.

Log Injection/Log4Shell

Unsachgemäße Kodierung in Log-Nachrichten trug zu Schwachstellen wie Log4Shell (CVE-2021-44228) bei, bei denen JNDI-Lookups in Log-Nachrichten zu Remote Code Execution führten.


Tools zum Testen und Ausnutzen


CVE-Beispiele


Referenzen

  1. MITRE. "CWE-116: Improper Encoding or Escaping of Output." https://cwe.mitre.org/data/definitions/116.html

  2. OWASP. "XSS Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html