Unangemessene Kodierung für Ausgabekontext
Beschreibung
Unangemessene Kodierung für Ausgabekontext ist eine Ausgabeverarbeitungs-Schwachstelle, bei der Software ein Kodierungsschema anwendet, das nicht dem entspricht, was die nachgelagerte Komponente erwartet, oder eine Kodierung anwendet, die für den spezifischen Ausgabekontext ungeeignet ist. Selbst eng verwandte Kodierungen können Probleme verursachen, wenn sie nicht übereinstimmen. Zum Beispiel schützt HTML-Entity-Kodierung gegen XSS, wenn Daten in HTML-Body-Elementen platziert werden, aber dieselbe Kodierung ist unzureichend, wenn Daten in HTML-Attributen, URLs, JavaScript oder CSS-Kontexten platziert werden. Diese Diskrepanz kann die Grenzen zwischen Kontrolle und Daten aufbrechen und Angreifern ermöglichen, spezielle Elemente einzuschleusen, die Schutzmechanismen umgehen.
Risiko
Diese Schwachstelle ermöglicht Injection-Angriffe, indem sie Angreifern erlaubt, aus dem beabsichtigten Datenkontext auszubrechen. XSS-Angriffe werden möglich, wenn HTML-Kodierung für JavaScript-Kontext verwendet wird oder umgekehrt. SQL-Injection kann auftreten, wenn datenbankspezifische Kodierung nicht zur tatsächlich verwendeten Datenbank passt. Command-Injection kann aus unsachgemäßem Shell-Escaping resultieren. Das Risiko ist erhöt, weil Entwickler glauben können, sie hätten die Ausgabe ordnungsgemäß kodiert, was ein falsches Sicherheitsgefühl erzeugt. Sicherheits-Scanning-Tools können diese Probleme auch verpassen, wenn sie nur das Vorhandensein von Kodierung prüfen, nicht deren Angemessenheit.
Lösung
Verwenden Sie kontextsensitive Kodierung, die zum spezifischen Ausgabekontext passt. Verstehen Sie, wo Daten gerendert werden, und wenden Sie die geeignete Kodierung an. Für Webanwendungen: verwenden Sie HTML-Entity-Kodierung für HTML-Body, HTML-Attribut-Kodierung für Attribute, JavaScript-Kodierung für JavaScript-Strings, URL-Kodierung für URL-Parameter und CSS-Kodierung für Style-Kontexte. Verwenden Sie etablierte Kodierungsbibliotheken wie OWASP ESAPI oder Framework-bereitgestellte Kodierungsfunktionen. Verlassen Sie sich nie auf ein einzelnes Kodierungsschema für alle Kontexte. Erwägen Sie die Verwendung von Template-Engines mit automatischer kontextsensitiver Kodierung. Spezifizieren Sie Kodierungen explizit, anstatt sich auf Standardwerte zu verlassen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Integrität Anwendungsdaten modifizieren - Angreifer könnten Nachrichtenstruktur modifizieren, indem sie Kodierungsdiskrepanzen ausnutzen, um Steuerzeichen einzuschleusen. |
| Integrität, Vertraulichkeit, Verfügbarkeit | Bereich: Integrität, Vertraulichkeit, Verfügbarkeit Unerlaubten Code oder Befehle ausführen - Kontextunangemessene Kodierung ermöglicht Injection-Angriffe (XSS, SQL-Injection, Command-Injection). |
Beispielcode
Anfälliger Code
// Anfällig: htmlentities() für alle Kontexte verwenden
<?php
$username = $_POST['username'];
$picSource = $_POST['picsource'];
$picAltText = $_POST['picalttext'];
// Das funktioniert für HTML-Body-Kontext
echo "<title>Willkommen, " . htmlentities($username) . "</title>";
// Anfällig: htmlentities() ist unzureichend für HTML-Attribute
// Es kodiert standardmäßig keine einfachen Anführungszeichen!
echo "<img src='" . htmlentities($picSource) . "' alt='" .
htmlentities($picAltText) . "' />";
// Angriff: picAltText = "test' onload='alert(document.cookie)"
// Ergebnis: <img src='pic.jpg' alt='test' onload='alert(document.cookie)' />
?>
// Anfällig: HTML-Kodierung in JavaScript-Kontext verwendet
function vulnerableGreeting(name) {
// Anfällig: HTML-Kodierung schützt nicht JavaScript-Strings
const encodedName = htmlEncode(name);
// Benutzer kann einschleusen: '; alert('XSS'); //
document.getElementById('greeting').innerHTML =
'<script>var user = "' + encodedName + '";</script>';
}
function htmlEncode(str) {
return str.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
}
// Keines dieser Zeichen ist gefährlich im JS-String-Kontext
// Aber Anführungszeichen und Backslashes sind es - und sie werden nicht kodiert!
// Anfällig: URL-Kodierung für HTML-Ausgabe verwendet
public String vulnerableDisplay(String userInput) {
// Anfällig: URL-Kodierung ist falsch für HTML-Kontext
String encoded = URLEncoder.encode(userInput, "UTF-8");
// URL-Kodierung ersetzt Leerzeichen mit +, nicht HTML-Entities
// < wird zu %3C, nicht < - Browser interpretiert es möglicherweise trotzdem
return "<div>" + encoded + "</div>";
}
# Anfällig: HTML-Escaping für URL-Kontext verwenden
from html import escape
def vulnerable_redirect(user_input):
# Anfällig: HTML-Escape ist ungeeignet für URL-Kontext
escaped = escape(user_input)
# javascript:-URLs werden durch HTML-Escaping nicht neutralisiert
# Angriff: javascript:alert(document.cookie)
return f'<a href="{escaped}">Hier klicken</a>'
// Anfällig: Gleiche Kodierung für SQL und Anzeige
<?php
function vulnerable_search($query) {
// addslashes ist ungeeignet für modernes SQL (Prepared Statements verwenden)
// Es ist auch ungeeignet für HTML-Ausgabe
$escaped = addslashes($query);
// Anfällig für SQL: addslashes behandelt nicht alle Injections
$result = mysql_query("SELECT * FROM items WHERE name = '$escaped'");
// Anfällig für HTML: addslashes kodiert keine HTML-Sonderzeichen
echo "<p>Ergebnisse für: $escaped</p>";
}
?>
// Anfällig: CSS-Kontext mit HTML-Kodierung
function vulnerableSetBackground(color) {
const htmlEncoded = escapeHtml(color);
// Anfällig: HTML-Kodierung schützt nicht CSS-Kontext
// Angriff: color = "red; background-image: url('javascript:alert(1)')"
document.getElementById('box').style.cssText =
'background-color: ' + htmlEncoded;
}
Korrigierter Code
// Korrigiert: Kontextangemessene Kodierung
<?php
// OWASP ESAPI oder ähnliche Bibliothek verwenden
require_once 'ESAPI.php';
$esapi = ESAPI::getEncoder();
$username = $_POST['username'];
$picSource = $_POST['picsource'];
$picAltText = $_POST['picalttext'];
// HTML-Body-Kontext - HTML-Entity-Kodierung
echo "<title>Willkommen, " . $esapi->encodeForHTML($username) . "</title>";
// HTML-Attribut-Kontext - Attribut-Kodierung (inkludiert Anführungszeichen)
echo "<img src='" . $esapi->encodeForHTMLAttribute($picSource) . "' alt='" .
$esapi->encodeForHTMLAttribute($picAltText) . "' />";
// URL-Kontext
echo "<a href='" . $esapi->encodeForURL($userLink) . "'>Link</a>";
// JavaScript-Kontext
echo "<script>var name = '" . $esapi->encodeForJavaScript($username) . "';</script>";
// CSS-Kontext
echo "<div style='color: " . $esapi->encodeForCSS($userColor) . "'>";
?>
// Korrigiert: Kontextspezifische Kodierung für JavaScript
function fixedGreeting(name) {
// Für JavaScript-String-Kontext, JS-spezifische Zeichen kodieren
const jsEncoded = encodeForJavaScript(name);
// DOM-Manipulation anstatt innerHTML verwenden wenn möglich
const script = document.createElement('script');
script.textContent = 'var user = "' + jsEncoded + '";';
document.head.appendChild(script);
}
function encodeForJavaScript(str) {
return str.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\u2028/g, '\\u2028') // Zeilentrenner
.replace(/\u2029/g, '\\u2029'); // Absatztrenner
}
// Besser: Inline-Skripte vermeiden, data-Attribute verwenden
function betterGreeting(name) {
const element = document.getElementById('greeting');
element.dataset.userName = name; // Sicher in data-Attribut gespeichert
// Im separaten Skript lesen: element.dataset.userName
}
// Korrigiert: Geeigneten Encoder für jeden Kontext verwenden
import org.owasp.encoder.Encode;
public class FixedOutput {
public String displayInHtml(String userInput) {
// HTML-Body-Kontext
return "<div>" + Encode.forHtml(userInput) + "</div>";
}
public String displayInAttribute(String userInput) {
// HTML-Attribut-Kontext (behandelt Anführungszeichen)
return "<input value=\"" + Encode.forHtmlAttribute(userInput) + "\">";
}
public String displayInUrl(String userInput) {
// URL-Kontext
return "<a href=\"https://example.com?q=" +
Encode.forUriComponent(userInput) + "\">Link</a>";
}
public String displayInJavaScript(String userInput) {
// JavaScript-String-Kontext
return "<script>var data = '" +
Encode.forJavaScriptBlock(userInput) + "';</script>";
}
public String displayInCss(String userInput) {
// CSS-Kontext
return "<div style=\"color: " +
Encode.forCssString(userInput) + "\">Text</div>";
}
}
# Korrigiert: Kontextsensitive Kodierung für URLs
import urllib.parse
from markupsafe import Markup, escape
def fixed_redirect(user_input):
# Zuerst URL-Schema validieren
parsed = urllib.parse.urlparse(user_input)
if parsed.scheme not in ('http', 'https', ''):
# javascript:, data: und andere gefährliche Schemata ablehnen
user_input = '#'
# HTML-Attribut-Kodierung verwenden
escaped = escape(user_input)
return Markup(f'<a href="{escaped}">Hier klicken</a>')
# Besser: Allowlist-Ansatz verwenden
def better_redirect(redirect_path):
# Nur relative Pfade zu bekannten Orten erlauben
allowed_paths = ['/home', '/profile', '/settings']
if redirect_path not in allowed_paths:
redirect_path = '/home'
return Markup(f'<a href="{escape(redirect_path)}">Hier klicken</a>')
// Korrigiert: Ordnungsgemäße SQL- und HTML-Behandlung
<?php
// Für SQL: Prepared Statements verwenden, nicht Kodierung
function fixed_search($query) {
$pdo = get_database_connection();
// Korrigiert: Parametrisierte Abfrage für SQL
$stmt = $pdo->prepare("SELECT * FROM items WHERE name = ?");
$stmt->execute([$query]);
$results = $stmt->fetchAll();
// Korrigiert: Ordnungsgemäße HTML-Kodierung für Anzeige
echo "<p>Ergebnisse für: " . htmlspecialchars($query, ENT_QUOTES, 'UTF-8') . "</p>";
return $results;
}
?>
// Korrigiert: CSS-kontextspezifische Kodierung
function fixedSetBackground(color) {
// Gegen Allowlist für CSS-Werte validieren
const validColors = /^[a-zA-Z]+$|^#[0-9a-fA-F]{3,6}$|^rgb\(\d+,\s*\d+,\s*\d+\)$/;
if (!validColors.test(color)) {
color = 'transparent'; // Sicherer Standard
}
// Jetzt sicher zu verwenden
document.getElementById('box').style.backgroundColor = color;
}
// Für beliebige CSS-Werte, CSS.escape() verwenden (moderne Browser)
function setArbitraryCSS(property, value) {
// CSS.escape behandelt CSS-spezifische Kodierung
const safeValue = CSS.escape(value);
element.style.setProperty(property, safeValue);
}
Verwandte CWEs
- CWE-116: Unzureichende Kodierung oder Escaping von Ausgaben (Eltern)
- CWE-79: Unzureichende Neutralisierung von Eingaben während der Webseitengenerierung (verwandt - XSS)
- CWE-89: Unzureichende Neutralisierung spezieller Elemente in SQL-Befehlen (verwandt)
- CWE-78: Unzureichende Neutralisierung spezieller Elemente in OS-Befehlen (verwandt)
Referenzen
- MITRE Corporation. "CWE-838: Inappropriate Encoding for Output Context." https://cwe.mitre.org/data/definitions/838.html
- OWASP. "XSS Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- OWASP. "ESAPI Encoder." https://owasp.org/www-project-enterprise-security-api/