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
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Nachrichtenmanipulation Angreifer können die Struktur von Nachrichten, Abfragen oder Befehlen verändern. |
| Vertraulichkeit | Bereich: Datendiebstahl Durch unsachgemäße Kodierung ermöglichte Injection-Angriffe können sensible Daten extrahieren. |
| Zugriffskontrolle | Bereich: 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
-
Burp Suite -- Kodierung in verschiedenen Kontexten testen.
-
OWASP ZAP -- automatisierte XSS-Erkennung.
-
XSS Hunter -- Erkennung von Blind XSS.
CVE-Beispiele
-
CVE-2021-44228 -- Log4j unsachgemäße Kodierung führt zu RCE.
-
CVE-2020-11022 -- jQuery XSS durch unsachgemäße Kodierung.
-
CVE-2019-11358 -- jQuery Prototype Pollution.
Referenzen
-
MITRE. "CWE-116: Improper Encoding or Escaping of Output." https://cwe.mitre.org/data/definitions/116.html
-
OWASP. "XSS Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html