Architektur mit Anzahl horizontaler Schichten außerhalb des erwarteten Bereichs

Beschreibung

Architektur mit Anzahl horizontaler Schichten außerhalb des erwarteten Bereichs tritt auf, wenn die Architektur eines Softwaresystems zu viele oder zu wenige horizontale Schichten im Vergleich zu branchenempfohlenen Standards enthält. CISQ (Consortium for Information and Software Quality) empfiehlt standardmäßig mindestens 4 Schichten und maximal 8 Schichten für Produktarchitekturen. Zu wenige Schichten deuten oft auf mangelhafte Trennung von Belangen hin, während zu viele Schichten unnötige Komplexität, Leistungsoverhead und Wartungsherausforderungen einführen können.

Risiko

Obwohl hauptsächlich ein architektonisches Qualitätsproblem, hat unsachgemäße Schichtung indirekte Sicherheitsimplikationen. Zu wenige Schichten bedeuten oft, dass Sicherheitslogik über die gesamte Codebasis verstreut ist, anstatt zentralisiert zu sein, was Audits erschwert und Umgehungen erleichtert. Systeme mit zu vielen Schichten führen zusätzliche Angriffsfläche durch Inter-Layer-Kommunikation ein und erhöhen das Risiko der Datenoffenlegung, wenn Informationen durch mehrere Grenzen geleitet werden. Komplexe Architekturen sind schwerer zu sichern, da das Verständnis des vollständigen Datenflusses die Navigation durch viele Abstraktionsebenen erfordert.

Lösung

Entwerfen Sie Architekturen mit einer angemessenen Anzahl horizontaler Schichten, typischerweise zwischen 4 und 8. Gängige Schichtmuster umfassen: Präsentationsschicht (UI), Anwendungs-/Service-Schicht, Geschäftslogik-Schicht und Datenzugriffsschicht. Fügen Sie sicherheitsspezifische Schichten (Authentifizierung, Autorisierung) als dedizierte Belange hinzu. Stellen Sie sicher, dass jede Schicht klare Verantwortlichkeiten und Schnittstellen hat. Dokumentieren Sie die Architektur und Schichtzwecke. Überprüfen Sie Architekturentscheidungen während Sicherheitsbewertungen.

Häufige Auswirkungen

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Wartbarkeit - Unsachgemäße Schichtung erschwert die Produktwartung und beeinflusst indirekt die Sicherheit, indem Schwachstellenerkennung und -behebung schwieriger werden.
AndereBereich: Ändere

Qualitätsverschlechterung - Architektonische Komplexität kann die Einführung von Sicherheitsmängeln erleichtern und deren Identifikation erschweren.

Beispielcode

Anfälliger Code

// ANFÄLLIG: Zu wenige Schichten - alles in einer Klasse
// Keine Trennung von Belangen, Sicherheit überall verstreut
public class VulnerableMonolithicApp {

    private Connection dbConnection;

    // Präsentation, Geschäftslogik und Datenzugriff alle gemischt
    public void handleUserRequest(HttpServletRequest request,
                                   HttpServletResponse response) throws Exception {

        // Direkte HTML-Generierung (Präsentation)
        PrintWriter out = response.getWriter();
        out.println("<html><body>");

        // Authentifizierung mit Geschäftslogik vermischt
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // Direktes SQL (Datenzugriff) - SQL-Injection anfällig
        Statement stmt = dbConnection.createStatement();
        ResultSet rs = stmt.executeQuery(
            "SELECT * FROM users WHERE username='" + username +
            "' AND password='" + password + "'"
        );

        if (rs.next()) {
            // Autorisierungsprüfung inline
            String role = rs.getString("role");
            if ("admin".equals(role)) {
                ResultSet data = stmt.executeQuery("SELECT * FROM sensitive_data");
                while (data.next()) {
                    out.println("<p>" + data.getString("info") + "</p>");
                }
            }
        }

        out.println("</body></html>");
    }

    // Sicherheitslogik kann nicht einfach auditiert oder gewartet werden
}

Korrigierter Code

// KORRIGIERT: Angemessene geschichtete Architektur (4-5 Schichten)

// Schicht 1: Präsentationsschicht - behandelt HTTP-Belange
@Controller
public class UserController {
    private final UserService userService;
    private final SecurityContext securityContext;

    @PostMapping("/login")
    public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
        // Behandelt nur HTTP-Belange, delegiert an Service-Schicht
        try {
            AuthResult result = userService.authenticate(
                request.getUsername(),
                request.getPassword()
            );
            return ResponseEntity.ok(new LoginResponse(result.getToken()));
        } catch (AuthenticationException e) {
            return ResponseEntity.status(401).build();
        }
    }

    @GetMapping("/data")
    @RequiresRole("ADMIN")  // Sicherheit ist deklarativ und zentralisiert
    public ResponseEntity<DataResponse> getSensitiveData() {
        List<DataItem> data = userService.getSensitiveData(
            securityContext.getCurrentUser()
        );
        return ResponseEntity.ok(new DataResponse(data));
    }
}

// Schicht 2: Service/Anwendungsschicht - Geschäftslogik
@Service
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final TokenService tokenService;
    private final AuditService auditService;

    public AuthResult authenticate(String username, String password) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new AuthenticationException("Ungültige Anmeldedaten"));

        if (!passwordEncoder.matches(password, user.getPasswordHash())) {
            auditService.logFailedLogin(username);
            throw new AuthenticationException("Ungültige Anmeldedaten");
        }

        auditService.logSuccessfulLogin(username);
        String token = tokenService.generateToken(user);
        return new AuthResult(user, token);
    }
}

// Schicht 3: Sicherheitsschicht - querschnittliche Sicherheitsbelange
@Component
public class SecurityService {
    private final TokenValidator tokenValidator;
    private final RoleChecker roleChecker;

    public void validateAccess(String token, String requiredRole) {
        User user = tokenValidator.validateAndExtract(token);
        if (!roleChecker.hasRole(user, requiredRole)) {
            throw new AccessDeniedException("Unzureichende Berechtigungen");
        }
    }
}

// Schicht 4: Datenzugriffsschicht - Datenbankoperationen
@Repository
public class UserRepository {
    private final JdbcTemplate jdbcTemplate;

    public Optional<User> findByUsername(String username) {
        // Parametrisierte Abfragen verhindern SQL-Injection
        return jdbcTemplate.queryForOptional(
            "SELECT * FROM users WHERE username = ?",
            new UserRowMapper(),
            username
        );
    }
}

CVE-Beispiele

Diese CWE ist für direkte CVE-Zuordnung als VERBOTEN markiert, da sie ein architektonisches Qualitätsproblem und keine direkte Sicherheitsschwachstelle darstellt.


Verwandte CWEs

  • CWE-710: Improper Adherence to Coding Standards (Eltern)
  • CWE-1006: Bad Coding Practices (Kategoriemitglied)
  • CWE-1130: CISQ Quality Measures - Maintainability (Kategoriemitglied)

Referenzen

  1. MITRE Corporation. "CWE-1044: Architecture with Number of Horizontal Layers Outside of Expected Range." https://cwe.mitre.org/data/definitions/1044.html

  2. CISQ. "Automated Source Code Quality Measures."

  3. Fowler, Martin. "Patterns of Enterprise Application Architecture."