Klonbare Klasse mit sensiblen Informationen
Beschreibung
Klonbare Klasse mit sensiblen Informationen ist eine Schwachstelle, bei der eine Klasse, die sensible Daten hält oder verarbeitet, das Cloneable-Interface implementiert oder anderweitig das Klonen erlaubt. Klonbare Klassen sind effektiv offene Klassen, da Daten in ihnen nicht versteckt werden können - jeder Code kann Kopien von Objekten erstellen, die sensible Informationen enthalten. Die Klon-Operation erstellt ein neues Objekt ohne den Konstruktor aufzurufen, was möglicherweise Sicherheitsüberprüfungen, Initialisierungslogik oder Zugriffskontrollen umgeht, die normalerweise die sensiblen Daten während der Objekterstellung schützen würden.
Risiko
Klassen, die sensible Daten wie Anmeldedaten, kryptografische Schlüssel, Finanzinformationen oder persönliche Daten enthalten, werden verwundbar, wenn sie klonbar sind. Angreifer können sensible Objekte klonen, um unbefugte Kopien zu erstellen, konstruktorbasierte Sicherheitsvalidierungen zu umgehen oder geschützte Informationen zu extrahieren. Das geklonte Objekt hat dieselben Daten wie das Original, existiert aber möglicherweise außerhalb des beabsichtigten Sicherheitskontexts. Klon-Operationen können auch sensible Daten leaken, wenn die clone-Methode böswillig überschrieben wird oder wenn flaches Klonen interne Referenzen offenlegt. Bei serialisierungsbasierten Angriffen kann das Klonen mit Deserialisierung kombiniert werden, um sensible Daten zu extrahieren oder zu manipulieren.
Lösung
Implementieren Sie niemals Cloneable für Klassen, die sensible Informationen enthalten. Wenn eine Klasse aus anderen Gründen klonbar sein muss, überschreiben Sie die clone-Methode als final und werfen Sie CloneNotSupportedException, um das Klonen explizit zu verhindern. Verwenden Sie Copy-Konstruktoren oder Factory-Methoden mit angemessenen Zugriffskontrollen als Alternativen, wenn kontrolliertes Kopieren benötigt wird. Für existierende Klassen, die klonbar sind, stellen Sie sicher, dass sensible Felder als transient markiert sind oder implementieren Sie eine benutzerdefinierte clone-Methode, die sensible Daten ordnungsgemäß schützt oder löscht. Überprüfen Sie Drittanbieterbibliotheken auf Klassen, die sensible Daten durch Klonen offenlegen könnten.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen - Sensible Daten können durch Klonen von Objekten extrahiert werden, was unbefugten Zugriff auf Anmeldedaten, Schlüssel oder persönliche Informationen ermöglicht. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Objekte können geklont werden, ohne den Konstruktor auszuführen, wodurch Sicherheitsüberprüfungen umgangen werden, die normalerweise während der Objektinstanziierung stattfinden würden. |
Beispielcode
Verwundbarer Code
// Verwundbar: Klonbare Klasse mit sensiblen Daten
public class VulnerableUserCredentials implements Cloneable {
private String username;
private String password;
private String sessionToken;
private byte[] privateKey;
public VulnerableUserCredentials(String username, String password) {
// Konstruktor führt Sicherheitsvalidierung durch
if (!validateCredentials(username, password)) {
throw new SecurityException("Ungültige Anmeldedaten");
}
this.username = username;
this.password = hashPassword(password);
this.sessionToken = generateSecureToken();
this.privateKey = loadPrivateKey(username);
}
// Verwundbar: Standard-Clone erlaubt Kopieren von Anmeldedaten
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // Kopiert alle Felder einschließlich sensibler Daten
}
private boolean validateCredentials(String user, String pass) {
// Sicherheitsvalidierung wird beim Klonen umgangen
return user != null && pass != null && pass.length() >= 8;
}
private String hashPassword(String password) {
return BCrypt.hashpw(password, BCrypt.gensalt());
}
private String generateSecureToken() {
return UUID.randomUUID().toString();
}
private byte[] loadPrivateKey(String username) {
// Privaten Schlüssel des Benutzers laden
return KeyStore.getPrivateKey(username);
}
// Getter...
}
// Angreifer nutzt Klonen aus
public class CredentialExploit {
public void exploit(VulnerableUserCredentials validCreds)
throws CloneNotSupportedException {
// Anmeldedaten-Objekt klonen - umgeht Validierung
VulnerableUserCredentials clonedCreds =
(VulnerableUserCredentials) validCreds.clone();
// Angreifer hat jetzt:
// - Kopie des Session-Tokens
// - Kopie des privaten Schlüssels
// - Alle Anmeldedaten ohne Authentifizierung
}
}
// Verwundbar: Schülerakten mit sensiblen Daten
public class VulnerableStudentRecord implements Cloneable {
private String name;
private String studentId;
private String socialSecurityNumber;
private String address;
private double gpa;
private List<String> medicalConditions;
// Konstruktor mit Zugriffskontrolle
public VulnerableStudentRecord(String name, String id,
AdminContext admin) {
if (!admin.hasPermission("CREATE_STUDENT_RECORD")) {
throw new SecurityException("Nicht autorisiert");
}
this.name = name;
this.studentId = id;
// ... weitere Felder initialisieren
}
// Verwundbar: Jeder kann sensible Schülerdaten klonen
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// Verwundbar: Finanztransaktion
public class VulnerableTransaction implements Cloneable {
private String transactionId;
private String accountNumber;
private double amount;
private String authorizationCode;
private byte[] signature;
// Verwundbar: Clone legt Finanzdaten offen
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// Verwundbar: Klonbar durch Vererbung
public class VulnerableSensitiveData extends CloneableBase {
// Erbt clone() von Elternklasse
private String apiKey;
private String secretToken;
// Auch ohne explizites Cloneable funktioniert clone() der Elternklasse
}
// Verwundbar: Klonbares Enum-ähnliches Muster
public class VulnerablePermission implements Cloneable {
public static final VulnerablePermission ADMIN =
new VulnerablePermission("ADMIN", 100);
public static final VulnerablePermission USER =
new VulnerablePermission("USER", 10);
private String name;
private int level;
private VulnerablePermission(String name, int level) {
this.name = name;
this.level = level;
}
// Verwundbar: Erlaubt Klonen von "Singleton"-Berechtigungen
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Lösungscode
// Behoben: Klasse verhindert explizit das Klonen
public final class SecureUserCredentials {
private final String username;
private final String passwordHash;
private final String sessionToken;
private final byte[] privateKey;
public SecureUserCredentials(String username, String password) {
if (!validateCredentials(username, password)) {
throw new SecurityException("Ungültige Anmeldedaten");
}
this.username = username;
this.passwordHash = hashPassword(password);
this.sessionToken = generateSecureToken();
this.privateKey = loadPrivateKey(username);
}
// Behoben: Klonen explizit verhindern
@Override
public final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException(
"Klonen von Anmeldedaten ist nicht erlaubt"
);
}
// Behoben: Kein Cloneable-Interface implementiert
// Behoben: Klasse ist final - kann nicht unterklassiert werden, um Cloneable hinzuzufügen
private boolean validateCredentials(String user, String pass) {
return user != null && pass != null && pass.length() >= 8;
}
private String hashPassword(String password) {
return BCrypt.hashpw(password, BCrypt.gensalt());
}
private String generateSecureToken() {
return UUID.randomUUID().toString();
}
private byte[] loadPrivateKey(String username) {
return KeyStore.getPrivateKey(username);
}
// Behoben: Kontrollierte Kopie mit Sicherheitsüberprüfungen
public static SecureUserCredentials createAuthorizedCopy(
SecureUserCredentials original,
SecurityContext context) {
if (!context.canCopyCredentials(original.username)) {
throw new SecurityException("Nicht autorisiert zum Kopieren von Anmeldedaten");
}
// Neue Instanz durch Konstruktor mit ordnungsgemäßen Prüfungen erstellen
// Hinweis: Dies erfordert Re-Authentifizierung, nicht nur Kopieren
return new SecureUserCredentials(
original.username,
context.getAuthenticatedPassword()
);
}
}
// Behoben: Schülerakte, die nicht geklont werden kann
public final class SecureStudentRecord {
private final String name;
private final String studentId;
private final String socialSecurityNumber; // Verschlüsselt
private final String address;
private final double gpa;
private final List<String> medicalConditions;
private SecureStudentRecord(Builder builder, AdminContext admin) {
if (!admin.hasPermission("CREATE_STUDENT_RECORD")) {
throw new SecurityException("Nicht autorisiert");
}
this.name = builder.name;
this.studentId = builder.studentId;
this.socialSecurityNumber = encrypt(builder.ssn);
this.address = builder.address;
this.gpa = builder.gpa;
this.medicalConditions = Collections.unmodifiableList(
new ArrayList<>(builder.medicalConditions)
);
}
// Behoben: Keine clone-Methode - Klasse ist nicht Cloneable
// Behoben: Final-Klasse verhindert Unterklassierung
// Behoben: Autorisierter Zugriff auf sensible Daten
public String getSSN(AdminContext admin) {
if (!admin.hasPermission("VIEW_SSN")) {
throw new SecurityException("Nicht autorisiert für SSN-Ansicht");
}
auditLog("SSN abgerufen für: " + studentId);
return decrypt(socialSecurityNumber);
}
// Behoben: Kontrollierter Export mit Schwärzung
public StudentRecordDTO toDTO(AdminContext admin) {
StudentRecordDTO dto = new StudentRecordDTO();
dto.name = this.name;
dto.studentId = this.studentId;
dto.gpa = admin.hasPermission("VIEW_GPA") ? this.gpa : null;
// SSN wird niemals in DTO exportiert
return dto;
}
private String encrypt(String data) {
return EncryptionService.encrypt(data);
}
private String decrypt(String data) {
return EncryptionService.decrypt(data);
}
// Builder-Pattern für kontrollierte Konstruktion
public static class Builder {
// ... Builder-Felder und -Methoden
}
}
// Behoben: Transaktion, die sensible Daten schützt
public final class SecureTransaction {
private final String transactionId;
private final String maskedAccountNumber;
private final double amount;
private final byte[] encryptedAuthCode;
public SecureTransaction(TransactionRequest request,
SecurityContext context) {
if (!context.isAuthorized()) {
throw new SecurityException("Nicht autorisierte Transaktion");
}
this.transactionId = generateTransactionId();
this.maskedAccountNumber = maskAccount(request.getAccountNumber());
this.amount = request.getAmount();
this.encryptedAuthCode = encryptAuthCode(
generateAuthCode(),
context.getEncryptionKey()
);
}
// Behoben: Explizit Exception bei Clone-Versuch werfen
@Override
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException(
"Finanztransaktionen können nicht geklont werden"
);
}
private String maskAccount(String account) {
return "****" + account.substring(account.length() - 4);
}
private String generateAuthCode() {
return SecureRandom.generateAuthorizationCode();
}
private byte[] encryptAuthCode(String code, Key key) {
return Cipher.encrypt(code.getBytes(), key);
}
}
// Behoben: Unveränderliches Permission-Enum (kein Klonen möglich)
public enum SecurePermission {
ADMIN(100),
MODERATOR(50),
USER(10),
GUEST(1);
private final int level;
SecurePermission(int level) {
this.level = level;
}
public int getLevel() {
return level;
}
// Enums können nicht geklont werden - clone() wirft CloneNotSupportedException
}
CVE-Beispiele
Keine spezifischen CVEs sind in der MITRE-Datenbank für diese CWE aufgeführt. Das Schwachstellenmuster ist jedoch dokumentiert in:
- CERT Oracle Secure Coding Standard for Java (OBJ07-J)
- Java-Sicherheits-Best-Practices
Referenzen
- MITRE Corporation. "CWE-498: Cloneable Class Containing Sensitive Information." https://cwe.mitre.org/data/definitions/498.html
- CERT Oracle Secure Coding Standard for Java. "OBJ07-J. Sensitive classes must not let themselves be copied."
- Oracle. "Secure Coding Guidelines for Java SE."