Abhängigkeit von Laufzeitkomponente in generiertem Code

Beschreibung

Abhängigkeit von Laufzeitkomponente in generiertem Code tritt auf, wenn automatisch generierter Code von einer bestimmten Laufzeit-Unterstützungskomponente abhängt, um ordnungsgemäß ausgeführt zu werden. Code-Generatoren, Compiler oder Entwicklungs-Frameworks können Code produzieren, der ohne bestimmte Laufzeitbibliotheken, Frameworks oder Unterstützungsmodule nicht funktionieren kann. Dies erzeugt eine enge Kopplung zwischen dem generierten Code und seiner Laufzeitumgebung, was den Code weniger portabel und schwieriger unabhängig zu warten macht.

Risiko

Die Abhängigkeit von spezifischen Laufzeitkomponenten in generiertem Code hat indirekte Sicherheitsimplikationen. Sicherheitsschwachstellen in der Laufzeitkomponente betreffen allen generierten Code. Updates der Laufzeit können generierten Code unerwartet brechen. Der generierte Code kann nicht unabhängig von der Laufzeit auditiert werden. Versionsungleichheiten zwischen generiertem Code und Laufzeit können Sicherheitsprobleme verursachen. Die Bereitstellung erfordert die Verwaltung sowohl des generierten Codes als auch der Laufzeitabhängigkeiten. Sicherheitsfixes in der Laufzeit werden möglicherweise nicht angewendet, wenn sie die Kompatibilität brechen. Die undurchsichtige Natur von generiertem Code erschwert Sicherheitsüberprüfungen.

Lösung

Minimieren Sie Abhängigkeiten von Laufzeitkomponenten in Code-Generatoren. Generieren Sie wo möglich eigenständigen Code. Dokumentieren Sie alle Laufzeitabhängigkeiten klar. Verwenden Sie stabile, gut gewartete Laufzeitkomponenten. Implementieren Sie Versionsprüfungen zwischen generiertem Code und Laufzeit. Erwägen Sie, Code zu generieren, der Standardbibliotheksfunktionen anstelle benutzerdefinierter Laufzeiten verwendet. Bieten Sie Mechanismen zur Neugenerierung von Code bei Laufzeitänderungen. Testen Sie generierten Code mit verschiedenen Laufzeitversionen. Fügen Sie Laufzeitversionanforderungen in generierte Code-Kommentare oder Metadaten ein.

Häufige Auswirkungen

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Wartbarkeit - Generierter Code kann nicht ohne Verständnis der Laufzeitabhängigkeiten gewartet werden.
AndereBereich: Ändere

Reduzierte Portabilität - Code kann ohne spezifische Laufzeitkomponente nicht ausgeführt werden.
VerfügbarkeitBereich: Verfügbarkeit

DoS: Absturz - Laufzeitversionskonflikte können Abstürze verursachen.

Beispielcode

Anfälliger Code

// Anfällig: Generierter ORM-Code eng mit Laufzeit gekoppelt

// GENERIERTER CODE - NICHT BEARBEITEN
// Dieser Code wurde von MyORMGenerator v2.3 generiert

public class GeneratedUserRepository {

    // Anfällig: Abhängig von spezifischer Laufzeitkomponente
    private final MyORMRuntime runtime;
    private final MyORMSession session;

    public GeneratedUserRepository() {
        // Anfällig: Schlägt fehl, wenn MyORMRuntime nicht verfügbar
        this.runtime = MyORMRuntime.getInstance();
        this.session = runtime.openSession();
    }

    public User findById(Long id) {
        // Anfällig: Verwendet laufzeitspezifischen Abfragemechanismus
        return runtime.executeQuery(
            MyORMQuery.builder()
                .entity(User.class)
                .where("id", MyORMOperator.EQUALS, id)
                .build()
        ).getSingleResult();
    }

    public List<User> findAll() {
        // Anfällig: Laufzeitspezifische Paginierung
        return runtime.createFinder(User.class)
            .withPagination(MyORMPagination.unlimited())
            .execute();
    }

    public void save(User user) {
        // Anfällig: Laufzeit-Transaktionsverwaltung
        runtime.inTransaction(() -> {
            session.persist(user);
        });
    }
}

// Problem: Wenn MyORMRuntime-Version sich ändert oder nicht verfügbar ist,
// brechen ALLE generierten Repositories
# Anfällig: Generierter API-Client abhängig von Laufzeit

# AUTOMATISCH GENERIERTER CODE - NICHT ÄNDERN
# Generiert von APIClientGenerator v1.5
# Erfordert: api_runtime >= 2.0.0

from api_runtime import (
    APIRuntimeClient,
    RequestBuilder,
    ResponseParser,
    AuthenticationHandler,
    RetryPolicy,
    CircuitBreaker
)


class GeneratedUserServiceClient:
    """Generierter Client für UserService API."""

    def __init__(self, base_url: str):
        # Anfällig: Enge Kopplung an Laufzeit
        self._client = APIRuntimeClient(
            base_url=base_url,
            retry_policy=RetryPolicy.default(),
            circuit_breaker=CircuitBreaker.default()
        )
        self._auth = AuthenticationHandler.oauth2()

    def get_user(self, user_id: str):
        # Anfällig: Laufzeitspezifischer Request-Aufbau
        request = RequestBuilder() \
            .method('GET') \
            .path(f'/users/{user_id}') \
            .with_auth(self._auth) \
            .build()

        response = self._client.execute(request)
        return ResponseParser.parse(response, UserDTO)

    def create_user(self, user_data: dict):
        # Anfällig: Laufzeit übernimmt Serialisierung
        request = RequestBuilder() \
            .method('POST') \
            .path('/users') \
            .body(user_data) \
            .with_auth(self._auth) \
            .content_type('application/json') \
            .build()

        response = self._client.execute(request)
        return ResponseParser.parse(response, UserDTO)


# Problem: Upgrade von api_runtime kann alle generierten Clients brechen
# Sicherheitsfixes in api_runtime erfordern Testen aller generierten Codes
// Anfällig: Generierter Serialisierungscode mit Laufzeitabhängigkeit

// <auto-generated>
// Dieser Code wurde von SerializerGenerator v3.1 generiert
// Erfordert: MySerializer.Runtime >= 3.0
// </auto-generated>

using MySerializer.Runtime;
using MySerializer.Runtime.Attributes;
using MySerializer.Runtime.Converters;

[RuntimeSerializable]
public partial class GeneratedUserDTO
{
    // Anfällig: Laufzeitspezifische Attribute
    [RuntimeProperty("id", Required = true)]
    public long Id { get; set; }

    [RuntimeProperty("username")]
    [RuntimeValidation(MinLength = 3, MaxLength = 50)]
    public string Username { get; set; }

    [RuntimeProperty("email")]
    [RuntimeConverter(typeof(EmailConverter))]
    public string Email { get; set; }

    [RuntimeProperty("created_at")]
    [RuntimeConverter(typeof(ISO8601DateConverter))]
    public DateTime CreatedAt { get; set; }

    // Anfällig: Laufzeit-generierte Serialisierung
    public string Serialize()
    {
        return RuntimeSerializer.Serialize(this);
    }

    public static GeneratedUserDTO Deserialize(string json)
    {
        return RuntimeSerializer.Deserialize<GeneratedUserDTO>(json);
    }
}

// Problem: MySerializer.Runtime-Änderungen betreffen alle generierten DTOs
// Sicherheitsschwachstellen in Convertern betreffen allen generierten Code

Korrigierter Code

// Korrigiert: Generierter Code mit minimaler Laufzeitabhängigkeit

// GENERIERTER CODE
// Generiert von ImprovedORMGenerator v3.0
// Laufzeitabhängigkeit: Optional (fällt auf Standard-JDBC zurück)

public class GeneratedUserRepository implements UserRepository {

    private final DataSource dataSource;
    private final Optional<ORMRuntime> runtime;

    // Korrigiert: Kann mit oder ohne Laufzeit arbeiten
    public GeneratedUserRepository(DataSource dataSource) {
        this.dataSource = dataSource;
        this.runtime = ORMRuntime.tryCreate();
    }

    @Override
    public User findById(Long id) {
        // Korrigiert: Fallback auf Standard-JDBC wenn Laufzeit nicht verfügbar
        if (runtime.isPresent()) {
            return runtime.get().findById(User.class, id);
        }

        // Eigenständige Fallback-Implementierung
        return executeQuery(
            "SELECT id, username, email, created_at FROM users WHERE id = ?",
            ps -> ps.setLong(1, id),
            this::mapUser
        );
    }

    @Override
    public List<User> findAll() {
        if (runtime.isPresent()) {
            return runtime.get().findAll(User.class);
        }

        return executeQuery(
            "SELECT id, username, email, created_at FROM users",
            ps -> {},
            this::mapUser
        );
    }

    @Override
    public void save(User user) {
        if (runtime.isPresent()) {
            runtime.get().save(user);
            return;
        }

        // Eigenständige Save-Implementierung
        executeUpdate(
            "INSERT INTO users (username, email, created_at) VALUES (?, ?, ?)",
            ps -> {
                ps.setString(1, user.getUsername());
                ps.setString(2, user.getEmail());
                ps.setTimestamp(3, Timestamp.from(user.getCreatedAt()));
            }
        );
    }

    // Eigenständige Hilfsmethoden
    private <T> T executeQuery(String sql, PreparedStatementSetter setter,
                               ResultSetMapper<T> mapper) {
        try (Connection conn = dataSource.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            setter.set(ps);
            try (ResultSet rs = ps.executeQuery()) {
                // Ergebnisse mappen...
                return mapper.map(rs);
            }
        } catch (SQLException e) {
            throw new DataAccessException(e);
        }
    }

    private User mapUser(ResultSet rs) throws SQLException {
        // Eigenständiges Mapping
        User user = new User();
        user.setId(rs.getLong("id"));
        user.setUsername(rs.getString("username"));
        user.setEmail(rs.getString("email"));
        user.setCreatedAt(rs.getTimestamp("created_at").toInstant());
        return user;
    }
}
# Korrigiert: Generierter API-Client mit optionaler Laufzeit

# AUTOMATISCH GENERIERTER CODE
# Generiert von ImprovedAPIGenerator v2.0
# Laufzeit: Optional (verwendet Standard-requests-Bibliothek als Fallback)

from typing import Optional, Any
import json

# Versuche optionale Laufzeit zu importieren, falle auf Standardbibliothek zurück
try:
    from api_runtime import APIRuntimeClient
    HAS_RUNTIME = True
except ImportError:
    HAS_RUNTIME = False
    import requests


class GeneratedUserServiceClient:
    """Generierter Client mit optionaler Laufzeitabhängigkeit."""

    def __init__(self, base_url: str, api_key: Optional[str] = None):
        self._base_url = base_url.rstrip('/')
        self._api_key = api_key

        # Korrigiert: Optionale Laufzeit
        if HAS_RUNTIME:
            self._client = APIRuntimeClient(base_url=base_url)
        else:
            self._client = None
            self._session = requests.Session()

    def get_user(self, user_id: str) -> dict:
        """Benutzer nach ID abrufen."""
        if self._client:
            # Laufzeit verwenden wenn verfügbar
            return self._client.get(f'/users/{user_id}')

        # Eigenständiger Fallback
        response = self._session.get(
            f'{self._base_url}/users/{user_id}',
            headers=self._get_headers()
        )
        response.raise_for_status()
        return response.json()

    def create_user(self, user_data: dict) -> dict:
        """Neuen Benutzer erstellen."""
        if self._client:
            return self._client.post('/users', json=user_data)

        # Eigenständiger Fallback
        response = self._session.post(
            f'{self._base_url}/users',
            headers=self._get_headers(),
            json=user_data
        )
        response.raise_for_status()
        return response.json()

    def _get_headers(self) -> dict:
        """Request-Header abrufen."""
        headers = {'Content-Type': 'application/json'}
        if self._api_key:
            headers['Authorization'] = f'Bearer {self._api_key}'
        return headers


# Alternative: Vollständig eigenständigen Code generieren
class SelfContainedUserClient:
    """Vollständig eigenständiger Client ohne Laufzeitabhängigkeiten."""

    def __init__(self, base_url: str, api_key: Optional[str] = None):
        self._base_url = base_url.rstrip('/')
        self._api_key = api_key

    def get_user(self, user_id: str) -> dict:
        import urllib.request
        import urllib.error

        url = f'{self._base_url}/users/{user_id}'
        req = urllib.request.Request(url, headers=self._headers())

        try:
            with urllib.request.urlopen(req) as response:
                return json.loads(response.read().decode())
        except urllib.error.HTTPError as e:
            raise APIError(e.code, e.read().decode())

    def _headers(self) -> dict:
        headers = {'Content-Type': 'application/json'}
        if self._api_key:
            headers['Authorization'] = f'Bearer {self._api_key}'
        return headers
// Korrigiert: Generierte Serialisierung mit Standardbibliotheks-Fallback

// <auto-generated>
// Generiert von ImprovedSerializerGenerator v4.0
// Laufzeit: Optional (verwendet System.Text.Json als Fallback)
// </auto-generated>

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

public partial class GeneratedUserDTO
{
    // Korrigiert: Standardbibliotheks-Attribute funktionieren ohne benutzerdefinierte Laufzeit
    [JsonPropertyName("id")]
    public long Id { get; set; }

    [JsonPropertyName("username")]
    public string Username { get; set; }

    [JsonPropertyName("email")]
    public string Email { get; set; }

    [JsonPropertyName("created_at")]
    public DateTime CreatedAt { get; set; }

    // Korrigiert: Eigenständige Serialisierung mit Standardbibliothek
    private static readonly JsonSerializerOptions DefaultOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };

    public string Serialize()
    {
        return JsonSerializer.Serialize(this, DefaultOptions);
    }

    public static GeneratedUserDTO Deserialize(string json)
    {
        return JsonSerializer.Deserialize<GeneratedUserDTO>(json, DefaultOptions);
    }

    // Korrigiert: Validierung ist eigenständig
    public ValidationResult Validate()
    {
        var errors = new List<string>();

        if (string.IsNullOrEmpty(Username))
            errors.Add("Username ist erforderlich");
        else if (Username.Length < 3 || Username.Length > 50)
            errors.Add("Username muss zwischen 3 und 50 Zeichen haben");

        if (string.IsNullOrEmpty(Email))
            errors.Add("Email ist erforderlich");
        else if (!IsValidEmail(Email))
            errors.Add("Ungültiges Email-Format");

        return new ValidationResult(errors.Count == 0, errors);
    }

    private static bool IsValidEmail(string email)
    {
        // Einfache Email-Validierung ohne Laufzeitabhängigkeit
        var atIndex = email.IndexOf('@');
        if (atIndex < 1) return false;
        var dotIndex = email.LastIndexOf('.');
        return dotIndex > atIndex + 1 && dotIndex < email.Length - 1;
    }
}

public record ValidationResult(bool IsValid, IReadOnlyList<string> Errors);

CVE-Beispiele

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


Verwandte CWEs

  • CWE-710: Improper Adherence to Coding Standards (Eltern)
  • CWE-1006: Bad Coding Practices (Kategoriemitglied)
  • CWE-1104: Use of Unmaintained Third Party Components (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1101: Reliance on Runtime Component in Generated Code." https://cwe.mitre.org/data/definitions/1101.html
  2. Code Generation Best Practices.
  3. Dependency Management Guidelines.