Abhängigkeit von Paket-Ebenen-Geltungsbereich
Beschreibung
Abhängigkeit von Paket-Ebenen-Geltungsbereich ist eine Schwachstelle, bei der Code Java-Paketzugriffskontrollen fälschlicherweise als Sicherheitsgrenzen behandelt. Java-Pakete sind nicht inhärent geschlossen; sie existieren primär als Komfortfunktion für Entwickler zur Codeorganisation und Vermeidung versehentlichen Zugriffs, nicht als Sicherheitsmechanismus. Jeder Code kann sich als Teil jedes Pakets deklarieren, und da verteilter Java-Code durch Klassen in anderen JAR-Dateien, die dasselbe Paket beanspruchen, erweitert werden kann, bietet das Verlassen auf Paket-Geltungsbereich für Sicherheit keinen echten Schutz.
Risiko
Paket-Ebenen-Geltungsbereich bietet keine Sicherheitsgarantien in Java-Anwendungen. Angreifer können eigene Klassen erstellen, die sich als Teil eines Zielpakets deklarieren, und erhalten Zugriff auf alle paket-privaten Mitglieder. Dies ist besonders gefährlich für sensible Daten oder Methoden, die als geschützt angenommen wurden. In verteilten Umgebungen können mehrere JAR-Dateien Klassen zum selben Paket beitragen, was bösartigem Code den Zugriff auf vermeintlich geschützte Mitglieder ermöglicht. Die Schwachstelle ist besonders schwerwiegend, wenn Paket-Geltungsbereich zum Schutz sicherheitskritischer Daten wie Anmeldedaten, kryptographischer Schlüssel oder Autorisierungstoken verwendet wird.
Lösung
Verlassen Sie sich niemals auf Paket-Ebenen-Geltungsbereich für Sicherheit. Machen Sie sensible Daten wann immer möglich private und final. Verwenden Sie ordnungsgemäße Kapselung mit privaten Feldern und kontrollierten Zugriffsmethoden. Für sicherheitskritischen Code verwenden Sie Javas SecurityManager und Zugriffskontrollmechanismen. Erwägen Sie versiegelte Pakete (Java 15+), um externen Code vom Beitritt zum Paket zu verhindern. Implementieren Sie ordnungsgemäße Authentifizierung und Autorisierung auf API-Ebene anstatt sich auf Sprachebenen-Zugriffskontrollen zu verlassen. Verwenden Sie Verschlüsselung für sensible Daten anstatt sich auf Sichtbarkeitsmodifikatoren zu verlassen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Vertraulichkeit Anwendungsdaten lesen - Da Java-Pakete durch externen Code erweitert werden können, können paket-private Daten von bösartigen Klassen abgerufen werden, die sich als Teil des Pakets deklarieren. |
| Integrität | Umfang: Integrität Anwendungsdaten modifizieren - Paket-private Felder und Methoden können von unbefugtem Code, der dem Paket beitritt, abgerufen und modifiziert werden. |
Beispielcode
Anfälliger Code
// Anfällig: Verlassen auf Paket-Geltungsbereich für Sicherheit
package com.banking.security;
// Anfällig: Paket-private Klasse als geschützt angenommen
class InternalSecurityManager {
// Anfällig: Paket-privates Feld als sicher angenommen
static String masterKey = "super-geheimer-schlüssel-12345";
// Anfällig: Paket-private Methode als geschützt angenommen
static boolean validateAdminAccess(String token) {
return token.equals(masterKey);
}
// Paket-privates Hilfsmittel - Angreifer kann dies aufrufen
static void resetAllSessions() {
// Gefährliche Operation als durch Paket-Geltungsbereich geschützt angenommen
SessionStore.invalidateAll();
}
}
// Anfällig: Sensible Daten mit Paket-Geltungsbereich
package com.banking.data;
class CustomerDatabase {
// Anfällig: Paket-Geltungsbereich für sensible Daten
String[] customerSSNs = new String[1000];
String[] accountNumbers = new String[1000];
// Anfällig: Paket-private Methode legt Daten offen
String getSSN(int customerId) {
return customerSSNs[customerId];
}
}
// Angreifercode - kann sich als Teil desselben Pakets deklarieren
package com.banking.security; // Dasselbe Paket wie Ziel!
public class MaliciousAccessor {
public static void exploit() {
// Angreifer kann auf paket-private Mitglieder zugreifen
System.out.println("Master-Schlüssel: " + InternalSecurityManager.masterKey);
// Angreifer kann paket-private Methoden aufrufen
InternalSecurityManager.resetAllSessions();
// Angreifer kann Admin-Zugriff fälschen
boolean hasAccess = InternalSecurityManager.validateAdminAccess(
InternalSecurityManager.masterKey
);
}
}
// Anfällig: Konfiguration mit paket-privaten Feldern
package com.app.config;
public class AppConfiguration {
// Anfällig: Paket-Geltungsbereich für sensible Konfiguration
String databasePassword = "db_passwort_123";
String apiSecret = "api_geheimer_schlüssel";
// Öffentliche Methode aber verlässt sich darauf, dass Aufrufer im selben Paket sind
// um auf interne Felder zuzugreifen
public void initialize() {
// Nimmt an, nur vertrauenswürdiger Code kann Felder sehen
connectToDatabase(databasePassword);
initializeApi(apiSecret);
}
}
// Anfällig: Sicherheitsprüfung verlässt sich auf Paket-Geltungsbereich
class SecurityValidator {
// Paket-privat - angenommen nur interne Klassen können aufrufen
boolean bypassSecurityCheck = false;
public boolean isSecure(Request request) {
// Anfällig: bypassSecurityCheck kann vom Angreifer gesetzt werden
if (bypassSecurityCheck) {
return true; // Angreifer kann alle Prüfungen umgehen
}
return performActualValidation(request);
}
}
Korrigierter Code
// Korrigiert: Ordnungsgemäße Kapselung ohne Verlassen auf Paket-Geltungsbereich
package com.banking.security;
public final class SecureSecurityManager {
// Korrigiert: Privates, finales Feld - kann nicht abgerufen oder modifiziert werden
private static final String masterKey;
static {
// Korrigiert: Aus sicherer Quelle laden, nicht hartcodiert
masterKey = loadKeyFromSecureStore();
}
// Korrigiert: Kein direkter Zugriff auf Master-Schlüssel
// Stattdessen sichere Vergleichsmethode verwenden
public static boolean validateAdminAccess(String token) {
// Korrigiert: Konstantzeit-Vergleich um Timing-Angriffe zu verhindern
return MessageDigest.isEqual(
token.getBytes(StandardCharsets.UTF_8),
masterKey.getBytes(StandardCharsets.UTF_8)
);
}
// Korrigiert: Ordnungsgemäße Autorisierung für sensible Operationen erfordern
public static void resetAllSessions(AdminCredentials creds) {
if (!validateAdminCredentials(creds)) {
throw new SecurityException("Unbefugt");
}
// Audit-Log vor gefährlicher Operation
auditLog("Session-Reset durch: " + creds.getAdminId());
SessionStore.invalidateAll();
}
private static String loadKeyFromSecureStore() {
// Aus HSM, verschlüsselter Konfiguration oder sicherem Tresor laden
return SecureKeyVault.getKey("master-key");
}
private static boolean validateAdminCredentials(AdminCredentials creds) {
// Ordnungsgemäße Authentifizierungsprüfung
return AuthenticationService.validate(creds);
}
}
// Korrigiert: Ordnungsgemäße Datenkapselung
package com.banking.data;
public final class SecureCustomerDatabase {
// Korrigiert: Private Felder ohne direkten Zugriff
private final String[] customerSSNs;
private final String[] accountNumbers;
public SecureCustomerDatabase(int capacity) {
this.customerSSNs = new String[capacity];
this.accountNumbers = new String[capacity];
}
// Korrigiert: Kontrollierter Zugriff mit Autorisierungsprüfung
public String getSSN(int customerId, UserContext context) {
// Korrigiert: Autorisierung vor Rückgabe sensibler Daten verifizieren
if (!AuthorizationService.canAccessSSN(context, customerId)) {
throw new SecurityException("Nicht autorisiert für SSN-Zugriff");
}
// Korrigiert: Zugriff auf sensible Daten protokollieren
AuditLog.logDataAccess(context.getUserId(), "SSN", customerId);
// Korrigiert: Maskierte Daten zurückgeben außer voller Zugriff gewährt
if (context.hasFullSSNAccess()) {
return customerSSNs[customerId];
} else {
return maskSSN(customerSSNs[customerId]);
}
}
private String maskSSN(String ssn) {
return "XXX-XX-" + ssn.substring(ssn.length() - 4);
}
}
// Korrigiert: Sichere Konfigurationsverwaltung
package com.app.config;
public final class SecureAppConfiguration {
// Korrigiert: Privat, final und sicher geladen
private final String databasePassword;
private final String apiSecret;
// Korrigiert: Sicheres Laden der Konfiguration verwenden
private SecureAppConfiguration() {
// Aus verschlüsselter Konfiguration laden
EncryptedConfig config = EncryptedConfig.load();
this.databasePassword = config.getDecrypted("db.password");
this.apiSecret = config.getDecrypted("api.secret");
}
// Korrigiert: Singleton mit ordnungsgemäßer Synchronisation
private static volatile SecureAppConfiguration instance;
public static SecureAppConfiguration getInstance() {
if (instance == null) {
synchronized (SecureAppConfiguration.class) {
if (instance == null) {
instance = new SecureAppConfiguration();
}
}
}
return instance;
}
// Korrigiert: Keine Getter für sensible Daten
// Stattdessen funktionale Methoden bereitstellen, die Daten intern verwenden
public Connection getDatabaseConnection() {
return DatabasePool.getConnection(databasePassword);
}
public ApiClient getApiClient() {
return new ApiClient(apiSecret);
}
}
// Korrigiert: Unveränderlicher Sicherheitsvalidator
public final class SecureSecurityValidator {
// Korrigiert: Kein veränderbares Umgehungs-Flag
public boolean isSecure(Request request) {
// Korrigiert: Immer Validierung durchführen, kein Umgehungsmechanismus
return performActualValidation(request);
}
private boolean performActualValidation(Request request) {
return checkAuthentication(request) &&
checkAuthorization(request) &&
checkInputValidation(request) &&
checkRateLimiting(request);
}
}
// Korrigiert: Verwendung von Java 15+ versiegelten Klassen für stärkere Kapselung
package com.banking.security;
// Korrigiert: Versiegelte Klassenhierarchie - nur erlaubte Unterklassen
public sealed class SecurityToken
permits AdminToken, UserToken, ServiceToken {
private final String tokenValue;
private final Instant expiration;
protected SecurityToken(String tokenValue, Instant expiration) {
this.tokenValue = tokenValue;
this.expiration = expiration;
}
public boolean isValid() {
return Instant.now().isBefore(expiration);
}
}
// Nur diese Klassen können SecurityToken erweitern
public final class AdminToken extends SecurityToken {
private final Set<Permission> permissions;
public AdminToken(String token, Instant exp, Set<Permission> perms) {
super(token, exp);
this.permissions = Set.copyOf(perms); // Unveränderliche Kopie
}
}
CVE-Beispiele
Keine spezifischen CVEs sind in der MITRE-Datenbank für dieses CWE aufgelistet. Das Schwachstellenmuster ist jedoch dokumentiert in:
- Java-Sicherheits-Best-Practices-Dokumentation
- Seven Pernicious Kingdoms Taxonomie
Referenzen
- MITRE Corporation. "CWE-487: Reliance on Package-level Scope." https://cwe.mitre.org/data/definitions/487.html
- Oracle. "Secure Coding Guidelines for Java SE."
- OWASP. "Java Security Cheat Sheet."