Detaillierte Fehlermeldungen
CWE-209CWE-200OWASP A05:2021Aktualisiert 4. September 20265 Min. Lesezeit
Eine Fehlermeldung mit Stacktrace, Datenbankabfrage oder Dateipfad verrät einem Angreifer, wie Ihre Anwendung aufgebaut ist. Diese Information erspart ihm die Erkundungsarbeit und ermöglicht gezielte Folgeangriffe. Nutzern genügt eine neutrale Meldung mit einer Vorgangsnummer; die Einzelheiten gehören in Ihre eigenen Protokolle.
Eine Fehlermeldung ist geschrieben, um einer Entwicklerin zu helfen, und das gelingt ihr gut: Sie sagt genau, was schiefging, an welcher Stelle im Code, mit welchen Daten. Landet dieselbe Meldung bei einem Besucher, hilft sie einem Angreifer ebenso wirksam. Im Folgenden lesen Sie, was darin steht, was ein Angreifer damit anfängt und wie Sie Fehler behandeln, ohne Ihre Entwickler blind zu machen.
Was sind detaillierte Fehlermeldungen?
Von detaillierten Fehlermeldungen sprechen wir, wenn eine Anwendung bei einer unerwarteten Lage technische Informationen anzeigt, die für die Entwicklung gedacht sind. In der Praxis geht es um einen Stacktrace mit Dateipfaden und Zeilennummern, die gescheiterte SQL-Abfrage, die Version des Frameworks oder des Datenbankservers oder den Inhalt von Variablen zum Zeitpunkt des Fehlers.
Der Punkt ist nicht, dass eine einzelne solche Meldung unmittelbar zu einer Kompromittierung führt. Der Punkt ist, dass ein Angreifer seine Arbeit mit Erkundung beginnt: Welche Technik läuft hier, welche Versionen, wie ist der Code gegliedert, wie sehen die Abfragen aus? Eine detaillierte Fehlermeldung liefert das auf einen Schlag, ohne dass er danach suchen müsste.
Vergleichen Sie es mit einem Gebäude, an dessen Sicherungskastentür ein Plan der gesamten Elektroinstallation hängt. Für den Monteur ist das praktisch. Für jemanden mit bösen Absichten ist es der Grundriss, den er sonst hätte rekonstruieren müssen.
Was steht in einer solchen Fehlermeldung?
Verwundbar:
app.get('/rechnung/:id', async (req, res) => {
try {
const rechnung = await db.query(
'SELECT * FROM rechnungen WHERE id = ? AND kunde_id = ?',
[req.params.id, req.nutzer.kundeId],
);
res.json(rechnung);
} catch (fehler) {
res.status(500).send(fehler.stack); // alles an den Nutzer
}
});
Eine Anfrage mit einem unerwarteten Wert liefert dann so etwas:
Error: ER_PARSE_ERROR: You have an error in your SQL syntax near ''' AND kunde_id = 4471'
at Query.Sequence._packetToError (/opt/portal/node_modules/mysql/lib/...)
at /opt/portal/src/rechnungen/repository.js:88:19
at RechnungService.finde (/opt/portal/src/rechnungen/service.js:34:7)
In vier Zeilen steckt eine erhebliche Menge an Information. Die Datenbank ist MySQL. Die Anwendung läuft in /opt/portal. Der Code ist in eine Repository- und eine Service-Schicht gegliedert. Es gibt eine Spalte kunde_id, und ihr Wert für diesen Nutzer ist 4471. Und, am wichtigsten: Die Eingabe landet offenbar so in der Abfrage, dass ein einzelnes Anführungszeichen sie zerbricht, ein starkes Anzeichen für SQL-Injection. Was ein Angreifer sonst mit Dutzenden blinden Versuchen hätte feststellen müssen, steht hier schwarz auf weiß.
Sicher:
app.get('/rechnung/:id', async (req, res, next) => {
const rechnung = await rechnungen.finde(req.params.id, req.nutzer.kundeId)
.catch(next);
if (!rechnung) return res.status(404).json({ fehler: 'Nicht gefunden' });
res.json(rechnung);
});
// Eine zentrale Behandlung für alles, was schiefgeht
app.use((fehler, req, res, next) => {
const vorgang = randomUUID();
logger.error({ // vollständige Angaben, nur intern
vorgang,
nachricht: fehler.message,
stack: fehler.stack,
pfad: req.originalUrl,
nutzer: req.nutzer?.id,
});
res.status(500).json({
fehler: 'Es ist etwas schiefgegangen. Wenden Sie sich an unseren Kundendienst.',
vorgang, // verknüpft die Meldung mit dem Protokoll
});
});
Der Nutzer erhält eine brauchbare, aber nichtssagende Meldung mit einer Vorgangsnummer. Die Entwicklung verliert nichts: Der vollständige Stacktrace, der Pfad und der Nutzer stehen im Protokoll, verknüpft mit derselben Nummer. Ruft jemand mit der Vorgangsnummer beim Kundendienst an, ist der Vorfall mit einer einzigen Suche auffindbar.
Welche Auswirkungen haben ausführliche Fehlermeldungen?
Der Schweregrad ist meist niedrig bis mittel, denn das Preisgeben von Informationen verschafft für sich genommen keinen Zugang. Die Bedeutung liegt in der Beschleunigung, die es einem Angreifer verschafft.
Ein Angreifer, der Ihr Framework, die Versionen und den Aufbau Ihres Codes kennt, kann gezielt nach bekannten Schwachstellen genau dieser Versionen suchen, statt breit auszuprobieren. Interne Dateipfade sind bei Angriffen wie Path Traversal oder beim Hochladen von Dateien nützlich. Und ein Datenbankfehler, der die Abfrage preisgibt, verkürzt das Ausnutzen einer SQL-Injection von einem langwierigen blinden Verfahren auf eine Sache von Minuten.
Es gibt zudem ein Szenario, in dem die Fehlermeldung selbst bereits der Schaden ist. Enthält die Ausnahme den Inhalt von Variablen, können darin personenbezogene Daten, Token oder Zugangsdaten für einen externen Dienst stehen. Das geschieht häufiger als gedacht bei Fehlern in der Kommunikation mit einer anderen API, wo die vollständige Anfrage einschließlich des verwendeten Schlüssels in der Meldung landet.
Wie spürt man ausführliche Fehlermeldungen auf?
Ein Tester löst gezielt Fehler an Stellen aus, an denen die Anwendung Eingaben verarbeitet: ein Buchstabe, wo eine Zahl erwartet wird, ein Anführungszeichen in einem Textfeld, ein zu langer Wert, ein fehlender Parameter, eine fehlerhaft aufgebaute JSON-Anfrage. Anschließend wird betrachtet, was zurückkommt.
Zusätzlich werden die Ränder der Anwendung abgegangen: nicht vorhandene Pfade, falsche HTTP-Methoden, Uploads über der Grenze und Anfragen mit unerwarteten Headern. Gerade dort antwortet häufig der Webserver oder das Framework statt Ihres eigenen Codes, mit einer Standardseite, die mehr preisgibt. Ebenso wird geprüft, ob die API dieselbe Disziplin wahrt wie die Weboberfläche und ob irgendwo ein Debugmodus eingeschaltet ist, der ausführliche Angaben zeigt. AssistSec achtet dabei auch auf den Unterschied zwischen Antworten: Zwei neutrale Meldungen, die geringfügig voneinander abweichen, können zusammen dennoch verraten, welche Konten oder Datensätze existieren.
Wie verhindert man ausführliche Fehlermeldungen?
- Fangen Sie Fehler zentral ab und geben Sie Nutzern eine neutrale Meldung mit einer eindeutigen Vorgangsnummer.
- Schreiben Sie die vollständigen Angaben, also Stacktrace, Abfrage und Zusammenhang, ausschließlich in Ihre eigenen Protokolldateien.
- Schalten Sie Debug- und Entwicklungsmodus in jeder aus dem Internet erreichbaren Umgebung ab.
- Konfigurieren Sie auch die Standardfehlerseiten Ihres Webservers und Frameworks, nicht nur die Ihres eigenen Codes.
- Zeigen Sie keine Versionsangaben Ihres Frameworks, Servers oder Ihrer Datenbank in Fehlermeldungen oder Headern.
- Sorgen Sie dafür, dass APIs ein strukturiertes, neutrales Fehlerobjekt ohne die zugrunde liegende Ausnahme zurückgeben.
- Filtern Sie heikle Werte aus Ihren Protokolldateien, damit Token und personenbezogene Daten nicht darin landen.
- Halten Sie Meldungen, die sich unterscheiden könnten, gleich, damit sie keine bestehenden Konten oder Datensätze verraten.
- Prüfen Sie Fehlersituationen bewusst als Teil Ihres Abnahmeverfahrens, nicht nur den störungsfreien Ablauf.
Quellen
Häufige Fragen
Darf ich in einer Testumgebung vollständige Fehler anzeigen?
Ja, und das ist auch praktisch. Die Falle besteht darin, dass Testumgebungen häufig aus dem Internet erreichbar sind und denselben Aufbau haben wie die Produktion. Sorgen Sie dann dafür, dass diese Umgebung abgeschirmt ist, denn ein Stacktrace aus der Abnahme verrät praktisch dasselbe wie einer aus der Produktion.
Was sollte ich dem Nutzer stattdessen zeigen?
Eine kurze, neutrale Meldung, dass etwas schiefgegangen ist, mit einer eindeutigen Vorgangsnummer. Diese Nummer verknüpfen Sie in Ihren eigenen Protokollen mit den vollständigen Einzelheiten. Der Nutzer kann sie an Ihren Kundendienst weitergeben, und Sie geben nichts über die Ursache preis.
Ist eine Fehlermeldung ohne Stacktrace sicher?
Nicht automatisch. Auch der Text selbst kann verraten, was schiefging: Eine Meldung über einen doppelten Schlüssel bestätigt, dass ein Datensatz existiert, und ein Unterschied zwischen zwei Meldungen kann Benutzernamen oder gültige Kennungen offenlegen. Achten Sie darauf, was der Unterschied zwischen zwei Antworten aussagt.
Wie steht es um Fehlermeldungen aus einer API?
Dort gelten dieselben Regeln, und dagegen wird häufiger verstoßen, weil man annimmt, nur das eigene Frontend schaue mit. Geben Sie ein strukturiertes, neutrales Fehlerobjekt mit einem Code und einer Vorgangsnummer zurück und nie die zugrunde liegende Ausnahme oder Abfrage.
Verwandte Artikel
- SchwachstellenCWE-489A05:2021Debugmodus in der Produktion eingeschaltetEin aktiver Debugmodus oder Profiler zeigt Konfiguration, Abfragen und mitunter eine Konsole. Lesen Sie, wie das missbraucht wird und wie Sie es abschalten.
- SchwachstellenCWE-200A01:2021Information DisclosureInformation Disclosure erklärt: wie Stack Traces, .git-Verzeichnisse, Source Maps und zu großzügige API-Antworten Daten preisgeben.
- SchwachstellenCWE-16A05:2021Security MisconfigurationSecurity Misconfiguration erklärt: wie Standardpasswörter, Debug-Modi und offene Cloud-Buckets Angreifern Zugang geben, und wie Sie sich schützen.
- SchwachstellenCWE-89A03:2021SQL InjectionSQL Injection erklärt: wie Angreifer über ungefilterte Eingaben Ihre Datenbank auslesen oder verändern und wie Sie es mit Prepared Statements verhindern.
- SchwachstellenCWE-200A05:2021Versionsinformationen in HTTP-HeadernHeader wie Server und X-Powered-By nennen genau, welche Software Sie einsetzen. Lesen Sie, warum das gezieltes Scannen erleichtert.