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
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: 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
-
MITRE Corporation. "CWE-317: Cleartext Storage of Sensitive Information in GUI." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/317.html
-
Microsoft. "UI Automation Security Overview." https://docs.microsoft.com/en-us/dotnet/framework/ui-automation/ui-automation-security-overview
-
OWASP Foundation. "Secure Coding Practices." https://owasp.org/