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
| Auswirkung | Details |
|---|---|
| Andere | Bereich: Ändere Reduzierte Wartbarkeit - Verstreuter plattformspezifischer Code ist schwerer zu warten. |
| Andere | Bereich: Ändere Reduzierte Portabilität - Schwierig auf neue Plattformen oder Umgebungen zu portieren. |
| Integrität | Bereich: 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
- MITRE Corporation. "CWE-1100: Insufficient Isolation of System-Dependent Functions." https://cwe.mitre.org/data/definitions/1100.html
- Martin, Robert C. "Clean Architecture" - Dependency Rule.
- Gamma et al. "Design Patterns" - Bridge Pattern.