Unzureichende Isolierung oder Kompartimentierung

Beschreibung

Unzureichende Isolierung oder Kompartimentierung tritt auf, wenn eine Anwendung Komponenten, Prozesse oder Daten, die voneinander isoliert sein sollten, nicht ordnungsgemäß trennt. Dies umfasst das Ausführen von Komponenten mit mehr Privilegien als nötig, das Versäumnis Sandboxen oder Container zu verwenden, das Teilen von Ressourcen zwischen Sicherheitsdomänen und das Nichtimplementieren von Defense-in-Depth. Eine Kompromittierung einer Komponente führt zur Kompromittierung anderer.

Risiko

Die Kompromittierung einer Komponente führt zur vollständigen Systemkompromittierung. Privilegieneskalation von niedrig-privilegierten zu hoch-privilegierten Komponenten. Mandantenübergreifender Datenzugriff in Multi-Tenant-Systemen. Laterale Bewegung durch gemeinsam genutzte Ressourcen. Sensible Daten durch unsachgemäße Grenzen exponiert. Malware-Verbreitung durch nicht-isolierte Prozesse.

Lösung

Implementieren Sie ordnungsgemäße Prozessisolierung mit Containern oder Sandboxen. Wenden Sie das Prinzip der minimalen Rechte an. Verwenden Sie separate Datenbanken/Schemas pro Mandant. Implementieren Sie Netzwerksegmentierung. Verwenden Sie fähigkeitsbasierte Sicherheit. Trennen Sie Authentifizierung von Geschäftslogik. Wenden Sie Defense-in-Depth über alle Schichten an.

Häufige Konsequenzen

AuswirkungDetails
VertraulichkeitUmfang: Datenleck

Daten aus einer Domäne werden von einer anderen zugegriffen.
IntegritätUmfang: Kreuzkontamination

Eine Komponente beschädigt die Daten einer anderen.
VerfügbarkeitUmfang: Kaskadenausfall

Ein Ausfall bringt das gesamte System zum Stillstand.

Beispielcode + Lösungscode

Anfälliger Code

// ANFÄLLIG: Keine Isolierung zwischen Komponenten
public class VulnerableMonolithicApp {

    // Alle Komponenten teilen denselben Prozess und Privilegien
    private UserService userService;
    private PaymentService paymentService;
    private AdminService adminService;
    private FileService fileService;

    // ANFÄLLIG: Zahlungsservice kann auf Admin-Funktionen zugreifen
    public void processPayment(PaymentRequest request) {
        // Zahlungscode läuft mit vollen Anwendungsprivilegien
        // Kann auf userService, adminService, fileService zugreifen
        paymentService.process(request);

        // Wenn Zahlungscode kompromittiert ist, hat Angreifer Zugriff auf alles
    }

    // ANFÄLLIG: Einzelne Datenbank, alle Services teilen Zugriff
    private DataSource sharedDatabase;  // Jeder verwendet dieselbe Verbindung

    public void storeData(String component, String data) {
        // Alle Komponenten schreiben in dieselben Tabellen
        // Keine Sicherheit auf Zeilenebene
        sharedDatabase.execute("INSERT INTO data ...");
    }
}

// ANFÄLLIG: Multi-Tenant ohne Isolierung
public class VulnerableMultiTenantService {

    private DataSource db;  // Einzelne gemeinsame Datenbank

    public List<Order> getOrders(String tenantId) {
        // ANFÄLLIG: Verlasst sich nur auf WHERE-Klausel für Isolierung
        // SQL-Injection oder Bug könnte Daten anderer Mandanten exponieren
        return db.query(
            "SELECT * FROM orders WHERE tenant_id = ?",
            tenantId
        );
    }

    // ANFÄLLIG: Gemeinsamer Dateispeicher
    public void saveFile(String tenantId, String filename, byte[] data) {
        // Alle Mandanten teilen dasselbe Verzeichnis
        // Path-Traversal könnte auf Dateien anderer Mandanten zugreifen
        Path path = Paths.get("/data/uploads/" + filename);
        Files.write(path, data);
    }
}
# ANFÄLLIG: Python ohne Prozessisolierung
import os
from flask import Flask, request

app = Flask(__name__)

# ANFÄLLIG: Aller Code läuft im selben Prozess mit denselben Privilegien
class MonolithicApp:
    def __init__(self):
        # Einzelne Datenbankverbindung überall geteilt
        self.db = Database()

        # Keine Trennung der Zuständigkeiten
        self.user_service = UserService(self.db)
        self.payment_service = PaymentService(self.db)
        self.admin_service = AdminService(self.db)

    # ANFÄLLIG: Zahlungsverarbeitung kann auf Admin-DB zugreifen
    def process_payment(self, payment_data):
        # Wenn dies ausgenutzt wird, kann Angreifer auf Admin-Funktionen zugreifen
        result = self.payment_service.process(payment_data)

        # Selber Prozess, kann Admin-Funktionen aufrufen
        self.admin_service.do_something()

# ANFÄLLIG: Shell-Befehle ohne Sandboxing ausgeführt
@app.route('/convert', methods=['POST'])
def convert_file_vulnerable():
    filename = request.form['filename']

    # ANFÄLLIG: Wird im Hauptprozess-Kontext ausgeführt
    # Kann auf alle Anwendungsdateien und Ressourcen zugreifen
    os.system(f"convert {filename} output.pdf")

    return "Konvertiert"

# ANFÄLLIG: Multi-Tenant mit gemeinsamen Ressourcen
class VulnerableMultiTenant:
    def __init__(self):
        self.shared_db = Database()
        self.shared_cache = RedisCache()
        self.shared_storage = FileStorage('/data')

    def get_tenant_data(self, tenant_id, query):
        # ANFÄLLIG: Nur Anwendungsebene-Filterung
        # Datenbank erzwingt keine Isolierung
        return self.shared_db.execute(
            f"SELECT * FROM data WHERE tenant_id = '{tenant_id}' AND {query}"
        )
// ANFÄLLIG: Node.js monolithisch ohne Isolierung
const express = require('express');
const app = express();

// ANFÄLLIG: Alle Services im selben Prozess
class MonolithicServer {
    constructor() {
        this.db = new Database();

        // Alles teilt dieselben Ressourcen
        this.userService = new UserService(this.db);
        this.paymentService = new PaymentService(this.db);
        this.fileService = new FileService(this.db);
    }

    // ANFÄLLIG: Code-Ausführung ohne Sandboxing
    executeUserCode(code) {
        // Läuft im selben Kontext wie Anwendung
        // Kann auf alle globalen Objekte zugreifen
        return eval(code);
    }
}

// ANFÄLLIG: Multi-Tenant ohne Datenbank-Isolierung
class MultiTenantService {
    constructor() {
        this.pool = new DatabasePool();  // Gemeinsamer Pool
    }

    async getData(tenantId, table) {
        // ANFÄLLIG: Mandanten-Isolierung nur durch Abfragen
        // Nicht auf Datenbankebene erzwungen
        return await this.pool.query(
            `SELECT * FROM ${table} WHERE tenant_id = $1`,
            [tenantId]
        );
    }

    // ANFÄLLIG: Gemeinsamer Secrets-Manager
    async getSecret(tenantId, secretName) {
        // Alle Mandanten verwenden denselben Secrets-Speicher
        // Namenskonvention ist einziger Schutz
        return await secretsManager.get(`${tenantId}/${secretName}`);
    }
}
// ANFÄLLIG: Go ohne ordnungsgemäße Isolierung
package main

// ANFÄLLIG: Monolithisches Design
type Application struct {
    db           *sql.DB  // Einzelne gemeinsame Datenbank
    userService  *UserService
    adminService *AdminService
    config       *Config  // Gemeinsame Konfiguration mit allen Secrets
}

// ANFÄLLIG: Alle Anfragen im selben Prozess behandelt
func (app *Application) handleRequest(w http.ResponseWriter, r *http.Request) {
    // Benutzer-zugewandter Code kann auf Admin-Service zugreifen
    // Keine Prozessgrenze
    app.userService.HandleUser(w, r)
}

// ANFÄLLIG: Nicht vertrauenswürdigen Code ausführen
func (app *Application) runPlugin(pluginCode string) {
    // Läuft mit vollen Anwendungsprivilegien
    // Kein Sandboxing
    plugin := LoadPlugin(pluginCode)
    plugin.Execute(app)  // Plugin hat Zugriff auf alles
}

// ANFÄLLIG: Multi-Tenant gemeinsame Ressourcen
func (app *Application) getTenantData(tenantID string) []Data {
    // Keine Datenbank-Level Mandanten-Isolierung
    rows, _ := app.db.Query(
        "SELECT * FROM data WHERE tenant_id = $1",
        tenantID,
    )
    return parseRows(rows)
}

Korrigierter Code

// SICHER: Microservices mit ordnungsgemäßer Isolierung
public class IsolatedPaymentService {

    // SICHER: Dedizierte Datenbank mit begrenztem Zugriff
    private final DataSource paymentDatabase;

    // SICHER: Isolierte Konfiguration
    private final PaymentConfig config;

    public IsolatedPaymentService() {
        // Nur zahlungsbezogener Datenbankzugriff
        this.paymentDatabase = DataSourceBuilder.create()
            .url(System.getenv("PAYMENT_DB_URL"))
            .username(System.getenv("PAYMENT_DB_USER"))
            .build();

        // Begrenzte Konfiguration
        this.config = new PaymentConfig();
    }

    // SICHER: Kann nur Zahlungsoperationen ausführen
    public PaymentResult process(PaymentRequest request) {
        // Kein Zugriff auf User-Service, Admin-Service, etc.
        return processPayment(request);
    }
}

// SICHER: Multi-Tenant mit Datenbank-Level-Isolierung
public class IsolatedMultiTenantService {

    private final Map<String, DataSource> tenantDatabases;

    // SICHER: Separate Datenbank pro Mandant
    public DataSource getTenantDatabase(String tenantId) {
        return tenantDatabases.computeIfAbsent(tenantId, id -> {
            // Jeder Mandant bekommt eigene Datenbank
            return DataSourceBuilder.create()
                .url(String.format("jdbc:postgresql://db/%s_db", id))
                .build();
        });
    }

    public List<Order> getOrders(String tenantId) {
        // SICHER: Verwendet mandantenspezifische Datenbank
        DataSource ds = getTenantDatabase(tenantId);
        // Selbst SQL-Injection kann nicht auf andere Mandanten zugreifen
        return ds.query("SELECT * FROM orders");
    }

    // SICHER: Isolierter Dateispeicher pro Mandant
    public void saveFile(String tenantId, String filename, byte[] data) {
        // Validiere Dateinamen
        if (!isValidFilename(filename)) {
            throw new SecurityException("Ungültiger Dateiname");
        }

        // Jeder Mandant hat separaten Speicher
        Path tenantDir = Paths.get("/data/tenants", tenantId, "files");
        Path filePath = tenantDir.resolve(filename).normalize();

        // Verifiziere innerhalb des Mandantenverzeichnisses
        if (!filePath.startsWith(tenantDir)) {
            throw new SecurityException("Path-Traversal erkannt");
        }

        Files.write(filePath, data);
    }
}

// SICHER: Verwendung von Containern für Prozessisolierung
@Configuration
public class IsolatedProcessConfig {

    @Bean
    public CodeExecutor sandboxedExecutor() {
        // Führe nicht vertrauenswürdigen Code in isoliertem Container aus
        return new DockerExecutor(
            DockerConfig.builder()
                .image("sandbox:latest")
                .memoryLimit("256m")
                .cpuLimit(0.5)
                .networkMode("none")  // Kein Netzwerkzugriff
                .readOnlyRootFilesystem(true)
                .build()
        );
    }
}
# SICHER: Python mit ordnungsgemäßer Isolierung
import os
from multiprocessing import Process
import docker

# SICHER: Microservice mit begrenztem Umfang
class IsolatedPaymentService:
    def __init__(self):
        # Nur zahlungsspezifische Datenbank
        self.db = Database(os.environ['PAYMENT_DB_URL'])

        # Kein Zugriff auf Ressourcen anderer Services

    def process_payment(self, payment_data):
        # Kann nur Zahlungsoperationen ausführen
        return self.db.execute_payment(payment_data)

# SICHER: Sandboxed Code-Ausführung
class SandboxedExecutor:
    def __init__(self):
        self.docker_client = docker.from_env()

    def execute_untrusted_code(self, code, timeout=30):
        # Führe in isoliertem Container aus
        container = self.docker_client.containers.run(
            image='python-sandbox:latest',
            command=['python', '-c', code],
            detach=True,
            mem_limit='256m',
            cpu_period=100000,
            cpu_quota=50000,  # 50% CPU
            network_mode='none',  # Kein Netzwerk
            read_only=True,
            security_opt=['no-new-privileges'],
            cap_drop=['ALL']
        )

        try:
            result = container.wait(timeout=timeout)
            logs = container.logs()
            return logs.decode()
        finally:
            container.remove(force=True)

# SICHER: Multi-Tenant mit Datenbank-Isolierung
class IsolatedMultiTenant:
    def __init__(self):
        self.tenant_dbs = {}
        self.tenant_storage = {}

    def get_tenant_db(self, tenant_id):
        if tenant_id not in self.tenant_dbs:
            # Jeder Mandant bekommt separate Datenbank
            self.tenant_dbs[tenant_id] = Database(
                f"postgresql://db/{tenant_id}_db"
            )
        return self.tenant_dbs[tenant_id]

    def get_tenant_data(self, tenant_id, query):
        # Verwendet mandantenspezifische Datenbank
        db = self.get_tenant_db(tenant_id)
        # Kann nicht auf Daten anderer Mandanten zugreifen selbst mit SQL-Injection
        return db.execute(query)

    def get_tenant_storage(self, tenant_id):
        # Isolierter Speicher pro Mandant
        tenant_path = f"/data/tenants/{tenant_id}"
        if tenant_id not in self.tenant_storage:
            # Erstelle chroot-ähnliche Isolierung
            self.tenant_storage[tenant_id] = IsolatedStorage(tenant_path)
        return self.tenant_storage[tenant_id]

# SICHER: Prozessisolierung für sensible Operationen
class SecureProcessor:
    def process_sensitive_data(self, data):
        # Führe in separatem Prozess mit begrenzten Privilegien aus
        def isolated_work(input_queue, output_queue):
            # Privilegien abgeben
            os.setgid(65534)  # nobody
            os.setuid(65534)

            # Verarbeite Daten
            result = do_processing(input_queue.get())
            output_queue.put(result)

        from multiprocessing import Queue
        input_q, output_q = Queue(), Queue()
        input_q.put(data)

        p = Process(target=isolated_work, args=(input_q, output_q))
        p.start()
        p.join(timeout=30)

        return output_q.get()
// SICHER: Node.js mit Prozessisolierung
const { Worker } = require('worker_threads');
const { VM } = require('vm2');

// SICHER: Sandboxed Code-Ausführung
class SandboxedExecutor {
    executeUntrustedCode(code, timeout = 5000) {
        // Verwende VM2 für Sandbox-Ausführung
        const vm = new VM({
            timeout,
            sandbox: {
                // Exponiere nur sichere APIs
                console: {
                    log: (...args) => console.log('[sandbox]', ...args)
                }
            },
            eval: false,
            wasm: false
        });

        try {
            return vm.run(code);
        } catch (error) {
            return { error: error.message };
        }
    }

    // SICHER: Führe in separatem Worker-Thread aus
    async executeInWorker(code) {
        return new Promise((resolve, reject) => {
            const worker = new Worker(`
                const { parentPort } = require('worker_threads');
                try {
                    const result = eval(${JSON.stringify(code)});
                    parentPort.postMessage({ result });
                } catch (error) {
                    parentPort.postMessage({ error: error.message });
                }
            `, { eval: true });

            const timeout = setTimeout(() => {
                worker.terminate();
                reject(new Error('Ausführungs-Timeout'));
            }, 5000);

            worker.on('message', (msg) => {
                clearTimeout(timeout);
                resolve(msg);
            });
        });
    }
}

// SICHER: Multi-Tenant mit ordnungsgemäßer Isolierung
class IsolatedMultiTenantService {
    constructor() {
        this.tenantConnections = new Map();
    }

    getTenantConnection(tenantId) {
        if (!this.tenantConnections.has(tenantId)) {
            // Jeder Mandant bekommt dedizierte Datenbank
            const connection = new Database({
                host: 'db',
                database: `tenant_${tenantId}`,
                user: `tenant_${tenantId}_user`,
                // Mandantenspezifische Anmeldedaten
                password: process.env[`TENANT_${tenantId}_DB_PASS`]
            });
            this.tenantConnections.set(tenantId, connection);
        }
        return this.tenantConnections.get(tenantId);
    }

    async getData(tenantId, query) {
        // Verwendet mandantenspezifische Datenbank
        const db = this.getTenantConnection(tenantId);
        return await db.query(query);
    }
}

Ausgenutzt in der Praxis

Container-Ausbrüche

Mangelnde ordnungsgemäße Container-Isolierung für Host-Zugriff ausgenutzt.

Multi-Tenant-Datenlecks

Gemeinsamer Datenbankzugriff führt zu mandantenübergreifender Exponierung.

Laterale Bewegung

Kompromittierung einer Komponente führt zu vollständigem Systembruch.


Tools zum Testen/Ausnutzen

  • Container-Sicherheitsscanner.

  • Tools zur Erkennung lateraler Bewegung.

  • Multi-Tenant-Isolierungstests.


CVE-Beispiele

  • CVE-2020-15257: Container-Escape über gemeinsame Namespaces.

  • Cloud Multi-Tenancy-Isolierungsfehler.


Referenzen

  1. MITRE. "CWE-653: Improper Isolation or Compartmentalization." https://cwe.mitre.org/data/definitions/653.html

  2. NIST. "Security Isolation Guidelines."