Unzureichende Isolation systemabhängiger Funktionen

Beschreibung

Unzureichende Isolation systemabhängiger Funktionen tritt auf, wenn ein Produkt systemabhängige Funktionalität nicht in separate, eigenständige Module isoliert. Diese Designschwäche führt dazu, dass systemspezifischer Code in der gesamten Anwendung verstreut ist, anstatt in Abstraktionsschichten zentralisiert zu sein. Wenn Code, der von bestimmten Betriebssystemen, Hardware oder Laufzeitumgebungen abhängt, nicht ordnungsgemäß isoliert wird, wird es schwierig, die Software zu portieren, zu warten und konsistentes Sicherheitsverhalten über Plattformen hinweg sicherzustellen.

Risiko

Die fehlende Isolation systemabhängigen Codes hat indirekte Sicherheitsimplikationen. Plattformspezifische Sicherheitsmechanismen können inkonsistent in der Codebasis implementiert sein. Sicherheitspatches für plattformspezifische Probleme müssen an mehreren Stellen angewendet werden. Die Portierung auf neue Plattformen kann Sicherheitsschwachstellen einführen, wenn Systemabhängigkeiten nicht klar identifiziert sind. Das Testen der Sicherheit über Plattformen hinweg wird schwieriger. Code-Review für Sicherheit wird durch verstreuten plattformspezifischen Code erschwert. Sicherheitsrelevante Operationen wie Dateiberechtigungen, Prozessausführung und Kryptographie können sich auf verschiedenen Plattformen unterschiedlich verhalten.

Lösung

Erstellen Sie Abstraktionsschichten, die systemabhängige Funktionalität kapseln. Verwenden Sie Interface- oder abstrakte Klassenmuster, um plattformunabhängige APIs zu definieren. Implementieren Sie plattformspezifischen Code in dedizierten Modulen, die diese Interfaces implementieren. Wenden Sie das Dependency-Inversion-Prinzip an, um von Abstraktionen statt von konkreten Implementierungen abzuhängen. Verwenden Sie Konfigurations- oder Factory-Muster zur Auswahl geeigneter Implementierungen. Zentralisieren Sie Plattformerkennungslogik. Befolgen Sie etablierte Muster wie das Bridge-Pattern für Plattformabstraktion. Dokumentieren Sie Plattformabhängigkeiten klar. Testen Sie auf allen unterstützten Plattformen.

Häufige Auswirkungen

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Wartbarkeit - Verstreuter plattformspezifischer Code ist schwerer zu warten.
AndereBereich: Ändere

Reduzierte Portabilität - Schwierig auf neue Plattformen oder Umgebungen zu portieren.
IntegritätBereich: Integrität

Inkonsistentes Verhalten - Kann sich auf verschiedenen Plattformen unerwartet unterschiedlich verhalten.

Beispielcode

Anfälliger Code

// Anfällig: Systemabhängiger Code in der gesamten Anwendung verstreut
public class VulnerableFileManager {

    public void createSecureFile(String path, String content) {
        // Anfällig: OS-spezifischer Code mit Geschäftslogik vermischt
        String osName = System.getProperty("os.name").toLowerCase();

        if (osName.contains("windows")) {
            // Windows-spezifische Dateierstellung
            try {
                Path filePath = Paths.get(path);
                Files.write(filePath, content.getBytes());
                // Windows ACL-Behandlung hier verstreut
                AclFileAttributeView aclView = Files.getFileAttributeView(
                    filePath, AclFileAttributeView.class);
                // Windows-Berechtigungen setzen...
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else if (osName.contains("linux") || osName.contains("mac")) {
            // Unix-spezifische Dateierstellung
            try {
                Path filePath = Paths.get(path);
                Files.write(filePath, content.getBytes());
                // Unix-Berechtigungen hier verstreut
                Set<PosixFilePermission> perms = EnumSet.of(
                    PosixFilePermission.OWNER_READ,
                    PosixFilePermission.OWNER_WRITE);
                Files.setPosixFilePermissions(filePath, perms);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public String getConfigPath() {
        // Anfällig: Mehr OS-Prüfungen in der gesamten Anwendung verstreut
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.contains("windows")) {
            return System.getenv("APPDATA") + "\\MyApp\\config.ini";
        } else if (osName.contains("mac")) {
            return System.getProperty("user.home") + "/Library/MyApp/config.ini";
        } else {
            return System.getProperty("user.home") + "/.myapp/config.ini";
        }
    }

    public void executeCommand(String command) {
        // Anfällig: Plattformspezifische Ausführung mit Geschäftslogik vermischt
        String osName = System.getProperty("os.name").toLowerCase();
        try {
            Process process;
            if (osName.contains("windows")) {
                process = Runtime.getRuntime().exec("cmd.exe /c " + command);
            } else {
                process = Runtime.getRuntime().exec("/bin/sh -c " + command);
            }
            process.waitFor();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
# Anfällig: Plattformspezifischer Code überall vermischt
import os
import sys
import platform

class VulnerableSystemService:

    def get_temp_directory(self):
        # Anfällig: Plattformprüfung in Methode verstreut
        if sys.platform == 'win32':
            return os.environ.get('TEMP', 'C:\\Temp')
        elif sys.platform == 'darwin':
            return '/tmp'
        else:
            return '/tmp'

    def set_file_permissions(self, path, mode):
        # Anfällig: Plattformspezifische Berechtigungsbehandlung
        if sys.platform == 'win32':
            # Windows unterstützt chmod nicht - icacls verwenden
            import subprocess
            subprocess.run(['icacls', path, '/grant', 'Users:R'], check=True)
        else:
            os.chmod(path, mode)

    def get_username(self):
        # Anfällig: Verschiedene Ansätze für verschiedene Plattformen
        if sys.platform == 'win32':
            return os.environ.get('USERNAME', 'unknown')
        else:
            import pwd
            return pwd.getpwuid(os.getuid()).pw_name

    def open_browser(self, url):
        # Anfällig: Plattformspezifisches Browser-Öffnen
        if sys.platform == 'win32':
            os.startfile(url)
        elif sys.platform == 'darwin':
            os.system(f'open "{url}"')
        else:
            os.system(f'xdg-open "{url}"')

    def get_line_ending(self):
        # Anfällig: Zeilenenden im gesamten Code verstreut
        if sys.platform == 'win32':
            return '\r\n'
        else:
            return '\n'
// Anfällig: Plattformcode in C#-Anwendung verstreut
public class VulnerablePathManager
{
    public string GetAppDataPath()
    {
        // Anfällig: Plattformprüfungen mit Geschäftslogik vermischt
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            return Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                "Library", "Application Support");
        }
        else
        {
            return Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                ".config");
        }
    }

    public void CreateHiddenFile(string path)
    {
        // Anfällig: Mehr plattformspezifischer Code
        File.Create(path).Close();

        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            File.SetAttributes(path, FileAttributes.Hidden);
        }
        // Auf Unix wird Datei durch '.' am Anfang des Namens versteckt
        // Diese Logik ist jetzt zwischen Erstellung und Benennung aufgeteilt
    }

    public string GetPathSeparator()
    {
        // Anfällig: Plattformspezifische Pfadbehandlung verstreut
        return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\\" : "/";
    }
}

Korrigierter Code

// Korrigiert: Plattformspezifischer Code in Abstraktionsschicht isoliert

// Plattformunabhängiges Interface
public interface FileSystemService {
    void createSecureFile(String path, String content) throws IOException;
    String getConfigPath();
    void executeCommand(String command) throws IOException;
}

// Windows-Implementierung
public class WindowsFileSystemService implements FileSystemService {

    @Override
    public void createSecureFile(String path, String content) throws IOException {
        Path filePath = Paths.get(path);
        Files.write(filePath, content.getBytes());

        // Windows-spezifische ACL-Behandlung an einem Ort
        AclFileAttributeView aclView = Files.getFileAttributeView(
            filePath, AclFileAttributeView.class);
        configureWindowsAcl(aclView);
    }

    @Override
    public String getConfigPath() {
        return System.getenv("APPDATA") + "\\MyApp\\config.ini";
    }

    @Override
    public void executeCommand(String command) throws IOException {
        ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", command);
        pb.inheritIO();
        Process process = pb.start();
        try {
            process.waitFor();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    private void configureWindowsAcl(AclFileAttributeView aclView) {
        // Windows-spezifische ACL-Konfiguration
    }
}

// Unix-Implementierung
public class UnixFileSystemService implements FileSystemService {

    @Override
    public void createSecureFile(String path, String content) throws IOException {
        Path filePath = Paths.get(path);
        Files.write(filePath, content.getBytes());

        // Unix-Berechtigungen an einem Ort
        Set<PosixFilePermission> perms = EnumSet.of(
            PosixFilePermission.OWNER_READ,
            PosixFilePermission.OWNER_WRITE);
        Files.setPosixFilePermissions(filePath, perms);
    }

    @Override
    public String getConfigPath() {
        String home = System.getProperty("user.home");
        return home + "/.myapp/config.ini";
    }

    @Override
    public void executeCommand(String command) throws IOException {
        ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", command);
        pb.inheritIO();
        Process process = pb.start();
        try {
            process.waitFor();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

// macOS-Implementierung (erweitert Unix mit Überschreibungen nach Bedarf)
public class MacOSFileSystemService extends UnixFileSystemService {

    @Override
    public String getConfigPath() {
        String home = System.getProperty("user.home");
        return home + "/Library/MyApp/config.ini";
    }
}

// Factory zur Erstellung der geeigneten Implementierung
public class FileSystemServiceFactory {

    public static FileSystemService create() {
        String osName = System.getProperty("os.name").toLowerCase();

        if (osName.contains("windows")) {
            return new WindowsFileSystemService();
        } else if (osName.contains("mac")) {
            return new MacOSFileSystemService();
        } else {
            return new UnixFileSystemService();
        }
    }
}

// Geschäftslogik verwendet Abstraktion
public class FixedFileManager {

    private final FileSystemService fileSystem;

    public FixedFileManager() {
        this.fileSystem = FileSystemServiceFactory.create();
    }

    // Konstruktor-Injection für Tests
    public FixedFileManager(FileSystemService fileSystem) {
        this.fileSystem = fileSystem;
    }

    public void createSecureFile(String path, String content) {
        try {
            // Plattformunabhängiger Code
            fileSystem.createSecureFile(path, content);
        } catch (IOException e) {
            throw new RuntimeException("Fehler beim Erstellen sicherer Datei", e);
        }
    }

    public String getConfigPath() {
        return fileSystem.getConfigPath();
    }
}
# Korrigiert: Plattformabstraktionsschicht in Python
from abc import ABC, abstractmethod
import os
import sys
from typing import Optional


# Plattformunabhängiges Interface
class PlatformService(ABC):

    @abstractmethod
    def get_temp_directory(self) -> str:
        pass

    @abstractmethod
    def set_file_permissions(self, path: str, mode: int) -> None:
        pass

    @abstractmethod
    def get_username(self) -> str:
        pass

    @abstractmethod
    def open_url(self, url: str) -> None:
        pass

    @property
    @abstractmethod
    def line_ending(self) -> str:
        pass


# Windows-Implementierung
class WindowsPlatformService(PlatformService):

    def get_temp_directory(self) -> str:
        return os.environ.get('TEMP', 'C:\\Temp')

    def set_file_permissions(self, path: str, mode: int) -> None:
        import subprocess
        # Unix-Modus auf Windows-Berechtigungen abbilden
        if mode & 0o444:  # Lesbar
            subprocess.run(['icacls', path, '/grant', 'Users:R'],
                          check=True, capture_output=True)

    def get_username(self) -> str:
        return os.environ.get('USERNAME', 'unknown')

    def open_url(self, url: str) -> None:
        os.startfile(url)

    @property
    def line_ending(self) -> str:
        return '\r\n'


# Unix-Implementierung
class UnixPlatformService(PlatformService):

    def get_temp_directory(self) -> str:
        return os.environ.get('TMPDIR', '/tmp')

    def set_file_permissions(self, path: str, mode: int) -> None:
        os.chmod(path, mode)

    def get_username(self) -> str:
        import pwd
        return pwd.getpwuid(os.getuid()).pw_name

    def open_url(self, url: str) -> None:
        import subprocess
        subprocess.run(['xdg-open', url], check=True)

    @property
    def line_ending(self) -> str:
        return '\n'


# macOS-Implementierung
class MacOSPlatformService(UnixPlatformService):

    def open_url(self, url: str) -> None:
        import subprocess
        subprocess.run(['open', url], check=True)


# Factory
class PlatformServiceFactory:

    @staticmethod
    def create() -> PlatformService:
        if sys.platform == 'win32':
            return WindowsPlatformService()
        elif sys.platform == 'darwin':
            return MacOSPlatformService()
        else:
            return UnixPlatformService()


# Geschäftslogik verwendet Abstraktion
class FixedSystemService:
    """Plattformunabhängiger Systemdienst."""

    def __init__(self, platform_service: Optional[PlatformService] = None):
        self._platform = platform_service or PlatformServiceFactory.create()

    def get_temp_directory(self) -> str:
        return self._platform.get_temp_directory()

    def set_file_permissions(self, path: str, mode: int) -> None:
        self._platform.set_file_permissions(path, mode)

    def get_username(self) -> str:
        return self._platform.get_username()

    def open_url(self, url: str) -> None:
        self._platform.open_url(url)

    def write_text_file(self, path: str, content: str) -> None:
        """Schreibt Textdatei mit korrekten Zeilenenden."""
        with open(path, 'w', newline=self._platform.line_ending) as f:
            f.write(content)
// Korrigiert: Plattformabstraktion in C#

// Plattformunabhängiges Interface
public interface IPlatformService
{
    string GetAppDataPath();
    void CreateHiddenFile(string path, string content);
    string PathSeparator { get; }
    string NormalizePath(string path);
}

// Windows-Implementierung
public class WindowsPlatformService : IPlatformService
{
    public string GetAppDataPath()
    {
        return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
    }

    public void CreateHiddenFile(string path, string content)
    {
        File.WriteAllText(path, content);
        File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden);
    }

    public string PathSeparator => "\\";

    public string NormalizePath(string path)
    {
        return path.Replace("/", "\\");
    }
}

// Unix/Linux-Implementierung
public class UnixPlatformService : IPlatformService
{
    public string GetAppDataPath()
    {
        var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
        return Path.Combine(home, ".config");
    }

    public void CreateHiddenFile(string path, string content)
    {
        // Auf Unix beginnen versteckte Dateien mit '.'
        var dir = Path.GetDirectoryName(path);
        var name = Path.GetFileName(path);
        var hiddenPath = Path.Combine(dir, "." + name.TrimStart('.'));
        File.WriteAllText(hiddenPath, content);
    }

    public string PathSeparator => "/";

    public string NormalizePath(string path)
    {
        return path.Replace("\\", "/");
    }
}

// macOS-Implementierung
public class MacOSPlatformService : UnixPlatformService
{
    public new string GetAppDataPath()
    {
        var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
        return Path.Combine(home, "Library", "Application Support");
    }
}

// Factory mit Dependency-Injection-Muster
public static class PlatformServiceFactory
{
    public static IPlatformService Create()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return new WindowsPlatformService();
        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            return new MacOSPlatformService();
        return new UnixPlatformService();
    }
}

// Geschäftslogik mit Dependency Injection
public class FixedPathManager
{
    private readonly IPlatformService _platform;

    public FixedPathManager(IPlatformService platform)
    {
        _platform = platform;
    }

    public string GetAppDataPath() => _platform.GetAppDataPath();

    public void CreateHiddenFile(string path, string content)
    {
        _platform.CreateHiddenFile(path, content);
    }

    public string BuildPath(params string[] segments)
    {
        return string.Join(_platform.PathSeparator, segments);
    }
}

CVE-Beispiele

Diese CWE ist für Schwachstellen-Zuordnung erlaubt, da unzureichende Plattformabstraktion zu Sicherheitsinkonsistenzen über Plattformen hinweg führen kann.


Verwandte CWEs

  • CWE-1061: Insufficient Encapsulation (Eltern)
  • CWE-1227: Encapsulation Issues (Kategoriemitglied)
  • CWE-1102: Reliance on Machine-Dependent Data Representation (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1100: Insufficient Isolation of System-Dependent Functions." https://cwe.mitre.org/data/definitions/1100.html
  2. Martin, Robert C. "Clean Architecture" - Dependency Rule.
  3. Gamma et al. "Design Patterns" - Bridge Pattern.