Klartext-Speicherung sensibler Informationen in der GUI

Beschreibung

Klartext-Speicherung sensibler Informationen in der GUI ist eine Schwachstelle, die auftritt, wenn ein Produkt sensible Informationen im Klartext in grafischen Benutzeroberflächenkomponenten speichert. GUI-Elemente wie Dialogboxen, Textfelder, Passwortfelder (mit fehlerhafter Maskierung), Listenfelder und Fenstereigenschaften können sensible Daten enthalten, die über GUI-Manipulations-APIs, Bildschirmaufnahme, Remote-Desktop-Sitzungen oder Barrierefreiheitstools zugänglich sein können. Selbst wenn Informationen visuell verborgen erscheinen (wie Passwort-Punkte), können die zugrunde liegenden Daten im Klartext im Speicher oder in den Eigenschaften der GUI-Komponente gespeichert sein und durch programmatische Inspektion zugänglich sein.

Risiko

Klartext-GUI-Speicherung exponiert sensible Daten durch mehrere Angriffsvektoren, die spezifisch für grafische Umgebungen sind. Angreifer können Barrierefreiheits-APIs verwenden, um Inhalte aus GUI-Elementen zu lesen, einschließlich Passwortfelder, die maskiert erscheinen. Bildschirmlesungssoftware, die für Barrierefreiheit konzipiert ist, kann Text aus UI-Komponenten extrahieren. Remote-Desktop- und Bildschirmfreigabe-Sitzungen können GUI-Inhalte für Zuschauer exponieren. GUI-Automatisierungstools und Test-Frameworks können Elementeigenschaften lesen. Malware kann GUI-Inhalte unter Verwendung von System-APIs für Fensterverwaltung auslesen. Speicherinspektion von GUI-Prozessen offenbart gespeicherte sensible Daten. Das Risiko wird auf gemeinsam genutzten oder kompromittierten Systemen verstärkt, wo mehrere Benutzer oder Anwendungen Zugriff auf GUI-Komponenteneigenschaften haben können.

Lösung

Speichern Sie niemals sensible Informationen im Klartext in GUI-Komponenten, selbst wenn sie visuell maskiert sind. Stellen Sie für Passwortfelder sicher, dass die zugrunde liegende Datenstruktur ebenfalls den Inhalt schützt, nicht nur die Anzeige. Verwenden Sie sichere String-Typen, die zufällige Speicherinspektion verhindern. Löschen Sie sensible Daten sofort nach der Verwendung aus GUI-Komponenten. Implementieren Sie sichere Passworteingabemechanismen, die keinen Klartext im Speicher behalten. Erwägen Sie die Verwendung hardwaregestützter sicherer Eingabemethoden, wo verfügbar. Deaktivieren Sie Zwischenablage-Zugriff für sensible Felder, um Kopieroperationen zu verhindern. Implementieren Sie GUI-Komponentensicherheitstests, um den Schutz sensibler Daten zu verifizieren. Verwenden Sie vom Betriebssystem bereitgestellte sichere Credential-Eingabedialoge, wenn verfügbar, anstelle von benutzerdefinierten Passwortfeldern.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Angreifer können über APIs, Barrierefreiheitstools oder Speicherinspektion auf GUI-Daten zugreifen und sensible Informationen lesen, selbst wenn sie visuell verborgen oder in der Oberfläche maskiert erscheinen.

Beispielcode

Anfälliger Code (C#/Java)

Die folgenden Beispiele demonstrieren Klartext-GUI-Speicherungs-Schwachstellen:

// Anfällig: Passwort in GUI-Komponenteneigenschaften gespeichert
using System;
using System.Windows.Forms;

public class VulnerableLoginForm : Form
{
    private TextBox usernameTextBox;
    private TextBox passwordTextBox;  // Reguläre TextBox, nicht maskiert!
    private string storedPassword;

    public VulnerableLoginForm()
    {
        usernameTextBox = new TextBox();
        usernameTextBox.Location = new Point(10, 10);

        // Anfällig: Reguläre TextBox für Passwort verwenden
        passwordTextBox = new TextBox();
        passwordTextBox.Location = new Point(10, 40);
        // Passwort im Klartext sichtbar!

        Controls.Add(usernameTextBox);
        Controls.Add(passwordTextBox);
    }

    // Anfällig: Passwort in Formulareigenschaft speichern
    public void StoreCredentials(string username, string password)
    {
        usernameTextBox.Text = username;
        // Anfällig: Passwort im Klartext in TextBox gespeichert
        passwordTextBox.Text = password;

        // Anfällig: Auch in Formularvariable gespeichert
        storedPassword = password;
        // Zugänglich via Reflection oder Speicherinspektion
    }

    // Anfällig: Passwort in Dialog für Screen-Reader sichtbar
    public void ShowPasswordDialog()
    {
        using (Form dialog = new Form())
        {
            TextBox passBox = new TextBox();
            passBox.Text = storedPassword;  // Klartext im Dialog!

            dialog.Controls.Add(passBox);
            dialog.ShowDialog();
        }
    }
}
// Anfällig: Java Swing Passworthandhabung
import javax.swing.*;
import java.awt.*;

public class VulnerableLoginPanel extends JPanel {

    private JTextField usernameField;
    private JTextField passwordField;  // Anfällig: Nicht JPasswordField!

    public VulnerableLoginPanel() {
        usernameField = new JTextField(20);

        // Anfällig: JTextField anstelle von JPasswordField verwenden
        passwordField = new JTextField(20);
        // Passwort im Klartext in der GUI sichtbar!

        add(new JLabel("Benutzername:"));
        add(usernameField);
        add(new JLabel("Passwort:"));
        add(passwordField);
    }

    // Anfällig: Passwort durch Tooltip exponieren
    public void setPasswordHint(String password) {
        // Anfällig: Passwort im Tooltip!
        passwordField.setToolTipText("Ihr Passwort ist: " + password);
    }

    // Anfällig: Passwort in zugänglicher Eigenschaft speichern
    public void storeCredentials(String username, String password) {
        usernameField.setText(username);
        passwordField.setText(password);  // Klartext!

        // Anfällig: Auch in Client-Property speichern
        passwordField.putClientProperty("stored_password", password);
    }
}

// Anfällig: Dialog mit Klartext-Passwortanzeige
public class VulnerablePasswordDialog {

    public void showStoredPassword(String password) {
        // Anfällig: Passwort im Dialog angezeigt
        JOptionPane.showMessageDialog(
            null,
            "Ihr Passwort ist: " + password,  // Klartext in GUI!
            "Passworterinnerung",
            JOptionPane.INFORMATION_MESSAGE
        );
    }
}
# Anfällig: Python tkinter Passworthandhabung
import tkinter as tk

class VulnerableLoginWindow:
    def __init__(self, root):
        self.root = root
        self.stored_password = None

        # Anfällig: Passwortfeld ohne Maskierung
        self.username_var = tk.StringVar()
        self.password_var = tk.StringVar()

        tk.Label(root, text="Benutzername:").pack()
        self.username_entry = tk.Entry(root, textvariable=self.username_var)
        self.username_entry.pack()

        tk.Label(root, text="Passwort:").pack()
        # Anfällig: Kein show='*' um Passwort zu maskieren
        self.password_entry = tk.Entry(root, textvariable=self.password_var)
        self.password_entry.pack()

    def save_credentials(self, username, password):
        # Anfällig: Klartext in GUI-Variablen speichern
        self.username_var.set(username)
        self.password_var.set(password)

        # Anfällig: Auch in Instanzvariable speichern
        self.stored_password = password

    def show_password_reminder(self):
        # Anfällig: Klartext-Passwort in Messagebox anzeigen
        tk.messagebox.showinfo(
            "Passworterinnerung",
            f"Ihr Passwort ist: {self.stored_password}"
        )

Korrigierter Code (C#/Java)

// Korrigiert: Sichere Passworthandhabung in GUI
using System;
using System.Windows.Forms;
using System.Security;
using System.Runtime.InteropServices;

public class SecureLoginForm : Form
{
    private TextBox usernameTextBox;
    private MaskedTextBox passwordTextBox;  // Korrigiert: Maskierte Eingabe
    private SecureString securePassword;

    public SecureLoginForm()
    {
        usernameTextBox = new TextBox();
        usernameTextBox.Location = new Point(10, 10);

        // Korrigiert: Ordnungsgemäße Passwortmaskierung verwenden
        passwordTextBox = new MaskedTextBox();
        passwordTextBox.PasswordChar = '*';
        passwordTextBox.Location = new Point(10, 40);

        // Korrigiert: Kopieren/Einfügen für Passwortfeld deaktivieren
        passwordTextBox.ShortcutsEnabled = false;

        Controls.Add(usernameTextBox);
        Controls.Add(passwordTextBox);
    }

    // Korrigiert: SecureString für Passwortspeicherung verwenden
    public void HandleLogin()
    {
        string username = usernameTextBox.Text;

        // Korrigiert: Sofort in SecureString konvertieren
        securePassword = new SecureString();
        foreach (char c in passwordTextBox.Text)
        {
            securePassword.AppendChar(c);
        }
        securePassword.MakeReadOnly();

        // Korrigiert: Textbox sofort leeren
        passwordTextBox.Clear();

        // Mit sicherem Passwort authentifizieren
        bool result = AuthenticateSecure(username, securePassword);

        // Korrigiert: SecureString nach Verwendung entsorgen
        securePassword.Dispose();
        securePassword = null;
    }

    private bool AuthenticateSecure(string username, SecureString password)
    {
        IntPtr passwordPtr = IntPtr.Zero;
        try
        {
            passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
            // Passwort kurz für Authentifizierung verwenden
            return VerifyCredentials(username, passwordPtr);
        }
        finally
        {
            // Korrigiert: Unverwalteten Speicher löschen
            if (passwordPtr != IntPtr.Zero)
            {
                Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);
            }
        }
    }

    // Korrigiert: Passwort niemals in Dialogen anzeigen
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Korrigiert: Sensible Daten bei Formularschließung löschen
            passwordTextBox?.Clear();
            securePassword?.Dispose();
        }
        base.Dispose(disposing);
    }
}
// Korrigiert: Sichere Java Swing Passworthandhabung
import javax.swing.*;
import java.awt.*;
import java.util.Arrays;

public class SecureLoginPanel extends JPanel {

    private JTextField usernameField;
    private JPasswordField passwordField;  // Korrigiert: JPasswordField verwenden

    public SecureLoginPanel() {
        usernameField = new JTextField(20);

        // Korrigiert: JPasswordField maskiert Eingabe und verwendet char[]
        passwordField = new JPasswordField(20);
        // Standard-Echo-Zeichen ist Kugel

        add(new JLabel("Benutzername:"));
        add(usernameField);
        add(new JLabel("Passwort:"));
        add(passwordField);
    }

    // Korrigiert: Sichere Credential-Handhabung
    public void handleLogin() {
        String username = usernameField.getText();

        // Korrigiert: Passwort als char-Array holen (veränderlich, löschbar)
        char[] password = passwordField.getPassword();

        try {
            // Mit Passwort authentifizieren
            boolean result = authenticate(username, password);

            if (result) {
                showSuccess();
            } else {
                showError();
            }
        } finally {
            // Korrigiert: Passwort aus Speicher löschen
            Arrays.fill(password, '\0');

            // Korrigiert: Passwortfeld leeren
            passwordField.setText("");
        }
    }

    // Korrigiert: Passwort niemals in Client-Properties speichern
    // Korrigiert: Passwort niemals in Tooltips oder Dialogen anzeigen

    private void showSuccess() {
        JOptionPane.showMessageDialog(
            this,
            "Anmeldung erfolgreich!",
            "Erfolg",
            JOptionPane.INFORMATION_MESSAGE
        );
    }

    private void showError() {
        JOptionPane.showMessageDialog(
            this,
            "Ungültige Anmeldedaten",  // Korrigiert: Passwort nicht offenbaren
            "Anmeldung fehlgeschlagen",
            JOptionPane.ERROR_MESSAGE
        );
    }

    private boolean authenticate(String username, char[] password) {
        // Sichere Authentifizierung implementieren
        return false;
    }
}
# Korrigiert: Sichere Python tkinter Passworthandhabung
import tkinter as tk
from tkinter import messagebox
import gc

class SecureLoginWindow:
    def __init__(self, root):
        self.root = root

        tk.Label(root, text="Benutzername:").pack()
        self.username_entry = tk.Entry(root)
        self.username_entry.pack()

        tk.Label(root, text="Passwort:").pack()
        # Korrigiert: show='*' verwenden um Passwort zu maskieren
        self.password_entry = tk.Entry(root, show='*')
        self.password_entry.pack()

        tk.Button(root, text="Anmelden", command=self.handle_login).pack()

    def handle_login(self):
        username = self.username_entry.get()
        password = self.password_entry.get()

        try:
            # Authentifizieren
            result = self.authenticate(username, password)

            if result:
                messagebox.showinfo("Erfolg", "Anmeldung erfolgreich!")
            else:
                # Korrigiert: Passwort nicht im Fehler offenbaren
                messagebox.showerror("Fehler", "Ungültige Anmeldedaten")

        finally:
            # Korrigiert: Passwortfeld sofort leeren
            self.password_entry.delete(0, tk.END)

            # Korrigiert: Passwortvariable löschen (Best-Effort in Python)
            password = None
            gc.collect()

    def authenticate(self, username, password):
        # Authentifizierung implementieren
        return False

    # Korrigiert: Passwort niemals in Dialogen anzeigen
    # Korrigiert: Passwort niemals in Instanzvariablen speichern

Die Korrektur verwendet ordnungsgemäße Passwortfelder mit Maskierung, SecureString wo verfügbar, und löscht sensible Daten nach der Verwendung.


Ausgenutzt in der Praxis

Dialog-Passwort-Exposition (Desktop-Anwendungen, 2002)

CVE-2002-1848 dokumentierte Anwendungen, die unverschlüsselte Passwörter in GUI-Dialogen speicherten, was lokalen Benutzern ermöglichte, über GUI-Inspektionstools auf Passwörter zuzugreifen.

Barrierefreiheitstool-Credential-Diebstahl (Verschiedene, Fortlaufend)

Angreifer haben Barrierefreiheits-APIs und Screen-Reader verwendet, um Anmeldedaten aus Passwortfeldern zu extrahieren, die nur die Anzeige maskieren, aber intern Klartext speichern.


Tools zum Testen/Ausnutzen

  • UI Spy — Windows-Tool zur Inspektion von UI-Automatisierungseigenschaften.

  • Accessibility Insights — Tool, das GUI-Elementeigenschaften einschließlich versteckten Text offenbaren kann.

  • Spy++ — Windows-Tool zur Untersuchung von Fenstereigenschaften und Nachrichten.


CVE-Beispiele

  • CVE-2002-1848 — Unverschlüsselte Passwörter in GUI-Dialog gespeichert.

Referenzen

  1. MITRE Corporation. "CWE-317: Cleartext Storage of Sensitive Information in GUI." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/317.html

  2. Microsoft. "UI Automation Security Overview." https://docs.microsoft.com/en-us/dotnet/framework/ui-automation/ui-automation-security-overview

  3. OWASP Foundation. "Secure Coding Practices." https://owasp.org/