Skip to content

Zugangsdaten in URLs im Log unkenntlich machen - #3780

Open
andreasmuellerka wants to merge 1 commit into
openWB:masterfrom
andreasmuellerka:redact-url-credentials-in-logs
Open

Zugangsdaten in URLs im Log unkenntlich machen#3780
andreasmuellerka wants to merge 1 commit into
openWB:masterfrom
andreasmuellerka:redact-url-credentials-in-logs

Conversation

@andreasmuellerka

Copy link
Copy Markdown

Problem

Ein Passwort, das als URL-userinfo übergeben wird (schema://benutzer:passwort@host/), steht im Klartext im Log. RedactingFilter greift nicht: Alle drei REDACTION_PATTERNS setzen an einem Feldnamen an (password=…, "password": "…"), und die userinfo einer URL nach RFC 3986 hat keinen.

Das ist kein Randfall. Mehrere SoC-Module — json, http, homeassistant, psacc — bieten ein freies url-Feld und keine getrennten Felder für Benutzer und Passwort. Für einen Endpunkt hinter Basic Auth ist es der einzige Weg, die Zugangsdaten in die URL zu schreiben, und requests unterstützt genau das.

Zwei Stellen protokollieren eine solche URL:

  • packages/modules/vehicles/json/soc.py gibt die konfigurierte URL auf Debug-Level aus → soc.log
  • packages/helpermodules/subdata.py protokolliert jede MQTT-Nachricht samt Payload, damit landet die Modulkonfiguration selbst in mqtt.log

An beiden Handlern hängt bereits ein RedactingFilter. Die Absicht, Geheimnisse aus diesen Dateien herauszuhalten, ist also vorhanden — es fehlte lediglich das Muster für diese Form.

Reproduktion

Ein JSON-SoC-Modul mit https://benutzer:geheim@nas.local/soc.json konfiguriert und Debug-Logging aktiviert, ergibt auf dem aktuellen master:

soc.log:  … url="https://benutzer:geheim@nas.local/soc.json" soc-pattern="soc" …
mqtt.log: … Payload: {"type": "json", "configuration": {"url": "https://benutzer:geheim@nas.local/soc.json"}}

Mit dieser Änderung steht in beiden Dateien https://benutzer:***REDACTED***@nas.local/soc.json.

Änderung

Ein Muster mehr in redact_sensitive_info(), damit wirkt es für jeden Handler, an dem bereits ein RedactingFilter hängt:

URL_CREDENTIALS_PATTERN = (r'(\w+://[^/\s:@]*):[^/\s]+@', r'\1:***REDACTED***@')

Der Benutzername bleibt sichtbar, ersetzt wird nur das Passwort. Bei der Diagnose eines Authentifizierungsproblems ist die Auskunft, mit welchem Benutzer verbunden wurde, der nützliche Teil der Logzeile.

Der Wertteil ist bewusst greedy: Enthält das Passwort selbst ein @, reicht der Treffer bis zum letzten @ vor dem Host statt nur bis zum ersten. In allen übrigen Fällen sind beide Varianten identisch. Schrägstrich und Whitespace bleiben ausgeschlossen, dadurch kann ein Treffer nie über die Authority hinaus in Pfad oder Query laufen — eine Mailadresse in einem Query-Parameter bleibt unangetastet.

thread_errors.log

Die beiden Excepthooks in setup_logging() schreiben über open()/write() und umgehen damit das Logging-Framework und den Filter. Eine ungefangene Exception, die eine URL mit sich trägt — etwa ein InvalidURI aus einem Verbindungsaufruf —, landet dort im Klartext. Sie führen ihren Text jetzt durch dieselbe Funktion. Aus print_tb() wurde format_tb(), weil sich nur ein String filtern lässt; die Ausgabe bleibt unverändert.

Tests

Neu ist packages/helpermodules/logger_test.py mit zehn Fällen, darunter drei, die unverändert bleiben müssen: eine URL ohne Zugangsdaten, ein @ in einem Query-Parameter und eine Mailadresse hinter einer URL.

Ein dokumentierter Randfall: Heißt der Benutzer wie ein Eintrag aus KNOWN_SENSITIVE_FIELDS (token, secret, …), greift zusätzlich das bestehende Feldmuster und kürzt die URL auf ws://token=***REDACTED***, weil dessen Wertmuster [^\s&]+ auch / und @ erlaubt. Das Passwort ist auch in diesem Fall entfernt, es fehlen lediglich Host und Pfad in der Logzeile. Das Verhalten ist von der Reihenfolge der beiden Ersetzungen unabhängig und durch einen Test festgehalten.

Ein Passwort, das als URL-userinfo übergeben wird (schema://benutzer:passwort@host/),
steht im Klartext im Log. RedactingFilter greift nicht, weil alle drei
REDACTION_PATTERNS an einem Feldnamen ansetzen und die userinfo einer URL nach
RFC 3986 keinen hat.

Mehrere SoC-Module - json, http, homeassistant, psacc - bieten ein freies
url-Feld und keine getrennten Felder für Benutzer und Passwort. Für einen
Endpunkt hinter Basic Auth ist es der einzige Weg, die Zugangsdaten in die URL zu
schreiben. Zwei Stellen protokollieren eine solche URL:

- packages/modules/vehicles/json/soc.py gibt die konfigurierte URL auf
  Debug-Level aus, das landet in soc.log
- packages/helpermodules/subdata.py protokolliert jede MQTT-Nachricht samt
  Payload, damit landet die Modulkonfiguration selbst in mqtt.log

An beiden Handlern hängt bereits ein RedactingFilter. Die Absicht, Geheimnisse
aus diesen Dateien herauszuhalten, ist also vorhanden - es fehlte lediglich das
Muster für diese Form.

Das neue Muster wirkt in redact_sensitive_info() und damit für jeden Handler, an
dem bereits ein RedactingFilter hängt. Der Benutzername bleibt sichtbar, ersetzt
wird nur das Passwort: Bei der Diagnose eines Authentifizierungsproblems ist die
Auskunft, mit welchem Benutzer verbunden wurde, der nützliche Teil der Logzeile.

Der Wertteil ist bewusst greedy. Enthält das Passwort selbst ein @, reicht der
Treffer bis zum letzten @ vor dem Host statt nur bis zum ersten. In allen übrigen
Fällen sind beide Varianten identisch. Schrägstrich und Whitespace bleiben
ausgeschlossen, dadurch kann ein Treffer nie über die Authority hinaus in Pfad
oder Query laufen - eine Mailadresse in einem Query-Parameter bleibt unangetastet,
was ein Test abdeckt.

Die beiden Excepthooks schreiben über open()/write() in thread_errors.log und
umgehen damit das Logging-Framework und den Filter. Eine ungefangene Exception,
die eine URL mit sich trägt - etwa ein InvalidURI aus einem Verbindungsaufruf -,
landet dort im Klartext. Sie führen ihren Text jetzt durch dieselbe Funktion; aus
print_tb() wurde format_tb(), weil sich nur ein String filtern lässt, die Ausgabe
bleibt unverändert.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant