diff --git a/app/rdp_proxy/ws_tunnel.py b/app/rdp_proxy/ws_tunnel.py index 41025b1..6b2c905 100644 --- a/app/rdp_proxy/ws_tunnel.py +++ b/app/rdp_proxy/ws_tunnel.py @@ -100,7 +100,6 @@ async def rdp_tunnel( if cred_row is None: await websocket.close(code=4404) return - password = decrypt_secret(cred_row[0], associated_data=b"rdp_password") cursor = await conn.execute( "INSERT INTO sessions (user_id, host_id, protocol, client_ip) VALUES (?, ?, 'rdp', ?)", @@ -125,7 +124,16 @@ async def rdp_tunnel( end_reason = "logout" tunnel = None tasks: list[asyncio.Task] = [] + password = None try: + # Entschluesselung bewusst HIER (innerhalb des try/finally, NACH dem + # Anlegen der sessions-Zeile) statt vor dem INSERT: schlaegt sie fehl + # (z.B. cryptography.exceptions.InvalidTag bei einem nicht mehr zum + # KEK passenden Blob), landet der Fehler jetzt im Catch-all unten UND + # es existiert bereits ein Session-/Audit-Log-Eintrag dafuer -- vorher + # riss ein Fehler hier VOR jeglicher Protokollierung durch und die + # Sitzung verschwand spurlos (schwarzer Bildschirm, kein Log-Eintrag). + password = decrypt_secret(cred_row[0], associated_data=b"rdp_password") params = build_rdp_params(host, password.decode()) tunnel = await open_tunnel( guacd_host=settings.guacd_host, guacd_port=settings.guacd_port, @@ -156,6 +164,14 @@ async def rdp_tunnel( # (POST /admin/sessions/{id}/terminate, siehe app/security/active_sessions.py). end_reason = "terminated_by_admin" raise + except Exception as exc: + # Auffangnetz analog zu app/ssh_proxy/terminal_ws.py -- deckt u.a. + # cryptography.exceptions.InvalidTag (KEK passt nicht mehr zum + # verschluesselten RDP-Passwort) ab, die vorher unbehandelt bis vor + # das erste await in dieser Funktion durchriss und die Sitzung ohne + # jede Fehlermeldung/Protokollierung sofort beendete. + logger.exception("Unerwarteter Fehler in RDP-Sitzung %s: %s", session_id, exc) + end_reason = "error" finally: active_sessions.unregister(session_id) del password # Klartext-Passwort so schnell wie moeglich freigeben diff --git a/app/ssh_proxy/terminal_ws.py b/app/ssh_proxy/terminal_ws.py index e3af077..b629ca7 100644 --- a/app/ssh_proxy/terminal_ws.py +++ b/app/ssh_proxy/terminal_ws.py @@ -132,6 +132,26 @@ async def ssh_terminal(websocket: WebSocket, host_id: int): # (POST /admin/sessions/{id}/terminate, siehe app/security/active_sessions.py). end_reason = "terminated_by_admin" raise + except Exception as exc: + # Auffangnetz fuer alles, was NICHT asyncssh.Error ist (z.B. + # asyncssh.KeyImportError bei einem defekten/nicht mehr passenden + # Schluessel, oder cryptography.exceptions.InvalidTag bei + # decrypt_secret() falls der KEK nicht mehr zum verschluesselten + # Schluessel passt) -- diese Typen sind KEINE asyncssh.Error- + # Unterklassen und liefen bisher unbehandelt durch, wodurch die + # Sitzung ohne jede Fehlermeldung abrupt getrennt wurde und im Log + # irrefuehrend als reason=logout erschien (Default-Wert, der nie + # aktualisiert wurde). Mit logger.exception landet der volle + # Traceback jetzt im Verbindungslog. + logger.exception("Unerwarteter Fehler in SSH-Sitzung %s: %s", session_id, exc) + end_reason = "error" + try: + await websocket.send_json({ + "type": "error", + "message": f"Verbindung zum Zielsystem fehlgeschlagen (interner Fehler: {exc.__class__.__name__})", + }) + except Exception: + logger.debug("Fehlermeldung konnte nicht mehr an Client gesendet werden", exc_info=True) finally: active_sessions.unregister(session_id) if pump_task: