Verletzung sicherer Designprinzipien

Beschreibung

Verletzung sicherer Designprinzipien tritt auf, wenn Softwarearchitektur und -design etablierte Sicherheitsprinzipien nicht befolgen. Dies umfasst die Verletzung des Prinzips der geringsten Privilegien, Defense in Depth, sichere Standardeinstellungen, Einfachheit der Mechanismen, vollständige Vermittlung, offenes Design, Privilegientrennung, geringstes gemeinsames Mechanismus-Prinzip und psychologische Akzeptanz. Schlechtes Design führt zu systemischen Schwachstellen, die später schwer zu beheben sind.

Risiko

Architekturelle Schwachstellen durchdringen ganze Systeme. Einzelne Fehlerpunkte kompromittieren die gesamte Sicherheit. Übermäßige Privilegien ermöglichen größere Sicherheitsverletzungen. Fehlende Verteidigungsschichten ermöglichen einfache Ausnutzung. Komplexe Designs verbergen Sicherheitslücken. Schlechte Kompartimentierung ermöglicht laterale Bewegung. Design-Fehler erfordern kostspielige Neuentwicklungen zur Behebung.

Lösung

Wenden Sie Sicherheitsprinzipien bereits in der Designphase an. Implementieren Sie Defense in Depth. Befolgen Sie das Prinzip der geringsten Privilegien. Verwenden Sie sichere Standardeinstellungen. Halten Sie Sicherheitsmechanismen einfach. Überprüfen Sie die Autorisierung bei jedem Zugriff. Trennen Sie kritische Funktionen. Minimieren Sie gemeinsam genutzte Ressourcen. Entwerfen Sie für Benutzbarkeit und Sicherheit gemeinsam.

Häufige Auswirkungen

AuswirkungDetails
SicherheitBereich: Systemische Schwachstellen

Designfehler betreffen die gesamte Anwendung.
WartungBereich: Technische Schulden

Unsicheres Design erfordert umfangreiches Refactoring.
ComplianceBereich: Audit-Fehler

Verstöße gegen Sicherheitsstandards und Vorschriften.

Beispielcode und Lösung

Verwundbarer Code

// VERLETZUNG: Geringste Privilegien - Alles läuft als Admin
public class VulnerableService {

    // VERLETZUNG: Dienst verwendet Admin-Anmeldedaten für alles
    private DataSource adminConnection = createAdminConnection();

    public List<Product> getPublicProducts() {
        // Verwendet Admin-Verbindung für schreibgeschützte öffentliche Abfrage
        return adminConnection.query("SELECT * FROM products WHERE public = true");
    }

    public void deleteUser(String userId) {
        // Gleiche Admin-Verbindung
        adminConnection.execute("DELETE FROM users WHERE id = ?", userId);
    }
}

// VERLETZUNG: Defense in Depth - Einzelne Sicherheitsschicht
public class VulnerableSingleLayerSecurity {

    public void accessResource(String userId, String resourceId) {
        // VERLETZUNG: Nur eine Sicherheitsprüfung
        if (isAuthenticated(userId)) {
            // Keine Autorisierungsprüfung
            // Keine Eingabevalidierung
            // Keine Audit-Protokollierung
            return getResource(resourceId);
        }
    }
}

// VERLETZUNG: Sichere Standardeinstellungen - Standard ist Erlauben
public class VulnerableDefaultAllow {

    public boolean checkPermission(String userId, String action) {
        try {
            Permission perm = permissionService.get(userId, action);
            return perm.isAllowed();
        } catch (Exception e) {
            // VERLETZUNG: Standard ist Erlauben bei Fehler
            return true;
        }
    }
}

// VERLETZUNG: Einfachheit der Mechanismen - Überkomplizierte Sicherheit
public class VulnerableComplexSecurity {

    public boolean authenticate(Request req) {
        // VERLETZUNG: Komplex, schwer zu prüfen
        return checkHeader(req) &&
               checkCookie(req) &&
               checkSession(req) &&
               checkToken(req) &&
               checkCertificate(req) &&
               checkIPRange(req) &&
               checkTimeOfDay(req) &&
               checkMoonPhase(req) && // Scherz, aber illustriert Komplexität
               validateAllTheThings(req);
    }
}
# VERLETZUNG: Vollständige Vermittlung - Nicht jeden Zugriff prüfen
class VulnerableIncompleteMediation:
    def __init__(self):
        self.verified_users = set()

    def access_resource(self, user_id, resource_id):
        # VERLETZUNG: Prüft nur beim ersten Mal
        if user_id not in self.verified_users:
            if self.check_authorization(user_id, resource_id):
                self.verified_users.add(user_id)  # Für immer gecacht
            else:
                raise PermissionError()

        # Nachfolgende Zugriffe überspringen die Autorisierung
        return self.get_resource(resource_id)

# VERLETZUNG: Privilegientrennung - Ein Schlüssel für alles
class VulnerableSinglePrivilege:
    def __init__(self, master_key):
        # VERLETZUNG: Ein Schlüssel kontrolliert alles
        self.master_key = master_key

    def authenticate(self, key):
        # Master-Schlüssel gewährt vollen Zugriff
        return key == self.master_key

    def delete_data(self, key):
        if self.authenticate(key):
            self.db.delete_all()

    def read_secrets(self, key):
        if self.authenticate(key):
            return self.get_all_secrets()

# VERLETZUNG: Geringstes gemeinsames Mechanismus-Prinzip - Gemeinsame Ressourcen
class VulnerableSharedResources:
    # VERLETZUNG: Alle Mandanten teilen sich denselben Verbindungspool
    shared_pool = ConnectionPool()

    # VERLETZUNG: Alle Mandanten teilen sich denselben Cache
    shared_cache = Cache()

    # VERLETZUNG: Alle Mandanten teilen sich denselben Dateispeicher
    shared_storage = FileStorage('/data')

    def get_tenant_data(self, tenant_id, query):
        # Verlasst sich auf Abfrage zur Datenisolierung - nicht auf Ressourcenebene erzwungen
        return self.shared_pool.execute(
            f"SELECT * FROM data WHERE tenant_id = '{tenant_id}'"
        )
// VERLETZUNG: Mehrere Prinzipien in Webanwendung
class VulnerableWebApp {
    constructor() {
        // VERLETZUNG: Geringste Privilegien - Globaler Admin-Kontext
        this.db = new DatabaseConnection({ user: 'admin' });
    }

    // VERLETZUNG: Defense in Depth - Einzelne Auth-Prüfung
    async handleRequest(req) {
        if (req.cookies.session) {
            // Keine Token-Validierung
            // Kein CSRF-Schutz
            // Kein Rate-Limiting
            return this.processRequest(req);
        }
        return { error: 'Unauthorized' };
    }

    // VERLETZUNG: Sichere Standardeinstellungen
    async checkAccess(userId, resource) {
        try {
            const allowed = await this.permissionService.check(userId, resource);
            return allowed;
        } catch (error) {
            // VERLETZUNG: Fehler = erlauben
            console.error(error);
            return true;
        }
    }

    // VERLETZUNG: Vollständige Vermittlung - Auth-Entscheidungen cachen
    async getResource(userId, resourceId) {
        const cacheKey = `auth:${userId}`;

        // VERLETZUNG: Gecachte Auth-Entscheidung ohne Aktualisierung verwendet
        if (this.cache.has(cacheKey)) {
            return this.loadResource(resourceId);
        }

        if (await this.checkAccess(userId, resourceId)) {
            // Für immer cachen - Berechtigungsänderungen nicht reflektiert
            this.cache.set(cacheKey, true);
            return this.loadResource(resourceId);
        }

        throw new Error('Forbidden');
    }
}

// VERLETZUNG: Offenes Design - Sicherheit hängt von Geheimhaltung ab
const SECRET_ADMIN_PATH = '/xK9mN2pL/admin';  // "Versteckter" Admin

app.get(SECRET_ADMIN_PATH, (req, res) => {
    // Keine Authentifizierung - URL-Geheimhaltung ist die "Sicherheit"
    res.json(getAllAdminData());
});

Sichere Lösung

// KORREKT: Befolgt sichere Designprinzipien
public class SecureService {

    // PRINZIP: Geringste Privilegien - Separate Verbindungen pro Rolle
    private DataSource readOnlyConnection;
    private DataSource writeConnection;
    private DataSource adminConnection;

    // PRINZIP: Einfachheit der Mechanismen - Einfach, prüfbar
    public List<Product> getPublicProducts() {
        // Verwendet minimale Privilegien für die Operation
        return readOnlyConnection.query(
            "SELECT * FROM products WHERE public = true"
        );
    }

    @RequiresRole("ADMIN")
    @AuditLogged
    public void deleteUser(String adminUserId, String targetUserId) {
        // Verwendet Admin-Verbindung nur für Admin-Operationen
        adminConnection.execute("DELETE FROM users WHERE id = ?", targetUserId);
    }
}

// KORREKT: Defense in Depth - Mehrere Sicherheitsschichten
public class SecureMultiLayerSecurity {

    public Object accessResource(Request request, String resourceId) {
        // Schicht 1: Eingabevalidierung
        if (!validator.isValidResourceId(resourceId)) {
            throw new InvalidInputException();
        }

        // Schicht 2: Authentifizierung
        User user = authService.authenticate(request);
        if (user == null) {
            throw new AuthenticationException();
        }

        // Schicht 3: Autorisierung
        if (!authzService.canAccess(user, resourceId)) {
            throw new AuthorizationException();
        }

        // Schicht 4: Rate-Limiting
        if (!rateLimiter.allowRequest(user.getId())) {
            throw new RateLimitException();
        }

        // Schicht 5: Ressource abrufen
        Object resource = resourceService.get(resourceId);

        // Schicht 6: Audit-Protokollierung
        auditLog.logAccess(user, resourceId);

        return resource;
    }
}

// KORREKT: Sichere Standardeinstellungen - Standard ist Verweigern
public class SecureDefaultDeny {

    public boolean checkPermission(String userId, String action) {
        // Standard ist Verweigern
        boolean allowed = false;

        try {
            Permission perm = permissionService.get(userId, action);
            if (perm != null) {
                allowed = perm.isAllowed();
            }
        } catch (Exception e) {
            // PRINZIP: Fail-Safe - bei Fehler verweigern
            log.error("Permission check failed, denying access", e);
            allowed = false;
        }

        return allowed;
    }
}

// KORREKT: Privilegientrennung - Mehrere Faktoren erforderlich
public class SecureSeparatedPrivilege {

    public boolean authorizeHighRiskAction(
            String userId,
            String password,
            String totpCode,
            String approverUserId
    ) {
        // PRINZIP: Mehrere unabhängige Faktoren
        // Faktor 1: Benutzer authentifiziert
        if (!authService.verifyPassword(userId, password)) {
            return false;
        }

        // Faktor 2: MFA verifiziert
        if (!totpService.verify(userId, totpCode)) {
            return false;
        }

        // Faktor 3: Genehmigung durch zweite Person (Funktionstrennung)
        if (!approvalService.isApproved(approverUserId, userId)) {
            return false;
        }

        return true;
    }
}
# KORREKT: Vollständige Vermittlung - Jeden Zugriff prüfen
class SecureCompleteMediation:
    def access_resource(self, user_id, resource_id):
        # PRINZIP: Immer bei jeder Anfrage verifizieren
        # Niemals auf gecachte Autorisierungsentscheidungen verlassen

        # Authentifizierung verifizieren
        user = self.auth_service.verify_session(user_id)
        if not user:
            raise AuthenticationError()

        # Autorisierung verifizieren (frische Prüfung, nicht gecacht)
        if not self.authz_service.can_access(user, resource_id):
            raise AuthorizationError()

        # Ressource abrufen
        resource = self.resource_service.get(resource_id)

        # Audit
        self.audit_log.log_access(user, resource_id)

        return resource

# KORREKT: Geringstes gemeinsames Mechanismus-Prinzip - Isolierte Ressourcen pro Mandant
class SecureIsolatedResources:
    def __init__(self):
        self.tenant_pools = {}
        self.tenant_caches = {}
        self.tenant_storage = {}

    def get_tenant_pool(self, tenant_id):
        # PRINZIP: Jeder Mandant bekommt isolierte Ressourcen
        if tenant_id not in self.tenant_pools:
            self.tenant_pools[tenant_id] = ConnectionPool(
                database=f'tenant_{tenant_id}_db',
                user=f'tenant_{tenant_id}_user'
            )
        return self.tenant_pools[tenant_id]

    def get_tenant_data(self, tenant_id, query):
        # Verwendet mandantenspezifische Verbindung
        # Isolation auf Datenbankebene, nicht nur Abfragefilterung
        pool = self.get_tenant_pool(tenant_id)
        return pool.execute(query)

# KORREKT: Defense-in-Depth-Implementierung
class SecureDefenseInDepth:
    def process_request(self, request):
        # Schicht 1: TLS/Transportsicherheit (auf Infrastrukturebene gehandhabt)

        # Schicht 2: Eingabevalidierung
        validated_input = self.validate_input(request)

        # Schicht 3: Authentifizierung
        user = self.authenticate(request)

        # Schicht 4: Autorisierung
        self.authorize(user, validated_input.action)

        # Schicht 5: Geschäftslogik mit Validierung
        result = self.execute_action(user, validated_input)

        # Schicht 6: Ausgabekodierung
        safe_output = self.encode_output(result)

        # Schicht 7: Audit-Protokollierung
        self.audit_log(user, validated_input.action, result.success)

        return safe_output
// KORREKT: Befolgt alle sicheren Designprinzipien
class SecureWebApp {
    constructor() {
        // PRINZIP: Geringste Privilegien - Verschiedene Verbindungen für verschiedene Bedürfnisse
        this.readOnlyDb = new DatabaseConnection({ user: 'reader', readOnly: true });
        this.writeDb = new DatabaseConnection({ user: 'writer' });
        this.adminDb = new DatabaseConnection({ user: 'admin' });
    }

    // PRINZIP: Defense in Depth - Mehrere Sicherheitsschichten
    async handleRequest(req) {
        // Schicht 1: Eingabevalidierung
        const validatedInput = this.validateInput(req.body);

        // Schicht 2: Rate-Limiting
        if (!await this.rateLimiter.check(req.ip)) {
            throw new RateLimitError();
        }

        // Schicht 3: Authentifizierung
        const user = await this.authenticate(req);

        // Schicht 4: CSRF-Validierung
        if (!this.validateCsrfToken(req, user)) {
            throw new CsrfError();
        }

        // Schicht 5: Autorisierung
        if (!await this.authorize(user, validatedInput.action)) {
            throw new AuthorizationError();
        }

        // Schicht 6: Anfrage verarbeiten
        const result = await this.processRequest(user, validatedInput);

        // Schicht 7: Audit-Protokollierung
        await this.auditLog(user, validatedInput.action, result);

        return result;
    }

    // PRINZIP: Sichere Standardeinstellungen - Bei Fehler verweigern
    async checkAccess(userId, resource) {
        try {
            const allowed = await this.permissionService.check(userId, resource);
            return allowed === true;  // Explizite true-Prüfung
        } catch (error) {
            // Protokollieren und verweigern
            this.logger.error('Access check failed', { userId, resource, error });
            return false;  // Fail-Safe: verweigern
        }
    }

    // PRINZIP: Vollständige Vermittlung - Frische Autorisierungsprüfung jedes Mal
    async getResource(userId, resourceId) {
        // Immer Autorisierung verifizieren (kein Caching von Auth-Entscheidungen)
        if (!await this.authorize(userId, resourceId)) {
            throw new ForbiddenError();
        }

        const resource = await this.loadResource(resourceId);

        // Zugriff protokollieren
        await this.auditLog({ userId, action: 'read', resourceId });

        return resource;
    }

    // PRINZIP: Privilegientrennung für risikoreiche Operationen
    async deleteAllUserData(userId, password, totpCode, adminApproval) {
        // Mehrere Faktoren erforderlich
        const passwordValid = await this.verifyPassword(userId, password);
        const totpValid = await this.verifyTotp(userId, totpCode);
        const approved = await this.verifyAdminApproval(adminApproval);

        if (!passwordValid || !totpValid || !approved) {
            throw new InsufficientPrivilegeError();
        }

        return this.performDeletion(userId);
    }
}

// PRINZIP: Offenes Design - Sicherheit hängt nicht von Geheimhaltung ab
// Admin-Routen sind dokumentiert, erfordern aber Authentifizierung
app.get('/api/admin/users',
    authenticate,
    requireRole('admin'),
    auditLog('admin_users_list'),
    adminController.listUsers
);

Ausgenutzt in der Praxis

Privilegien-Eskalation

Fehlendes Prinzip der geringsten Privilegien führte zu massiven Sicherheitsverletzungen.

Einzelne Fehlerpunkte

Fehlendes Defense in Depth ermöglichte vollständige Kompromittierung.

Gecachte Auth-Umgehung

Autorisierungs-Caching ermöglichte Zugriff nach Widerruf.


Tools zum Testen und Ausnutzen

  • Architektur-Review-Tools.

  • Bedrohungsmodellierungs-Frameworks.

  • Sicherheitsdesign-Checklisten.


CVE-Beispiele

  • Architekturelle Fehler in großen Anwendungen.

  • Schwachstellen auf Designebene.


Referenzen

  1. MITRE. "CWE-657: Violation of Secure Design Principles." https://cwe.mitre.org/data/definitions/657.html

  2. Saltzer und Schröder. "The Protection of Information in Computer Systems."