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
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Datenleck Daten aus einer Domäne werden von einer anderen zugegriffen. |
| Integrität | Umfang: Kreuzkontamination Eine Komponente beschädigt die Daten einer anderen. |
| Verfügbarkeit | Umfang: 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
-
MITRE. "CWE-653: Improper Isolation or Compartmentalization." https://cwe.mitre.org/data/definitions/653.html
-
NIST. "Security Isolation Guidelines."