Fehlerhafter Ressourcentransfer zwischen Sphären
Beschreibung
Fehlerhafter Ressourcentransfer zwischen Sphären tritt auf, wenn ein Produkt eine Ressource auf eine Weise an eine andere Sphäre überträgt, die die beabsichtigten Sicherheitsgrenzen verletzt. Dies umfasst die Übertragung sensibler Daten an nicht vertrauenswürdige Kontexte, den Import bösartiger Inhalte in vertrauenswürdige Kontexte oder das Überschreiten von Vertrauensgrenzen ohne ordnungsgemäße Validierung. Beispiele sind die Übergabe von Benutzereingaben an Systembefehle, die Deserialisierung nicht vertrauenswürdiger Daten und die Einbettung von Benutzerinhalten in privilegierte Kontexte.
Risiko
Nicht vertrauenswürdige Daten werden im privilegierten Kontext ausgeführt. Sensible Informationen lecken an unbefugte Sphären. Bösartiger Code wird durch Deserialisierung importiert. Domänenübergreifender Datendiebstahl durch unsachgemäße Übertragungen. Command Injection durch Benutzereingaben in Systemaufrufen. SQL Injection durch nicht vertrauenswürdige Daten in Abfragen.
Lösung
Validieren und bereinigen Sie Daten, die Vertrauensgrenzen überschreiten. Verwenden Sie sichere APIs, die Daten und Kontrolle nicht vermischen. Implementieren Sie ordnungsgemäße Kodierung bei der Datenübertragung. Vermeiden Sie die Deserialisierung nicht vertrauenswürdiger Daten. Verwenden Sie parametrisierte Schnittstellen. Wenden Sie das Prinzip der minimalen Rechte auf übertragene Ressourcen an.
Häufige Konsequenzen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Code-Ausführung Bösartige Daten werden im vertrauenswürdigen Kontext ausgeführt. |
| Vertraulichkeit | Bereich: Informationsoffenlegung Sensible Daten werden an nicht vertrauenswürdige Sphäre übertragen. |
| Autorisierung | Bereich: Privilegieneskalation Benutzerkontrollierte Daten erhalten privilegierten Zugriff. |
Beispielcode + Lösungscode
Verwundbarer Code
// VERWUNDBAR: Fehlerhafter Ressourcentransfer zwischen Sphären
import java.io.*;
// VERWUNDBAR: Benutzereingabe an Befehlsausführungssphäre übertragen
public class VulnerableTransfer {
public void executeCommand(String userInput) {
// VERWUNDBAR: Benutzerdaten an OS-Befehlssphäre übertragen
Runtime.getRuntime().exec("ls " + userInput);
}
// VERWUNDBAR: Deserialisierung nicht vertrauenswürdiger Daten
public Object deserializeFromNetwork(InputStream networkInput) throws Exception {
ObjectInputStream ois = new ObjectInputStream(networkInput);
// VERWUNDBAR: Nicht vertrauenswürdige Daten an Objektsphäre übertragen
return ois.readObject(); // Remote Code Execution möglich
}
// VERWUNDBAR: Benutzereingabe an SQL-Sphäre übertragen
public void queryDatabase(String userInput, Connection conn) throws SQLException {
Statement stmt = conn.createStatement();
// VERWUNDBAR: Benutzerdaten mit SQL-Befehlen vermischt
stmt.executeQuery("SELECT * FROM users WHERE name = '" + userInput + "'");
}
// VERWUNDBAR: Benutzerdaten an Logging-Sphäre übertragen
public void logUserAction(String username) {
// VERWUNDBAR: CRLF-Injection möglich - Benutzerdaten im Log
logger.info("Benutzer eingeloggt: " + username);
// Könnte gefälschte Log-Einträge injizieren
}
// VERWUNDBAR: Sensible Daten an Client-Sphäre übertragen
public void sendResponse(HttpServletResponse response, User user) throws IOException {
// VERWUNDBAR: Interne Daten an Client übertragen
response.getWriter().write(user.toJson()); // Enthält Passwort-Hash!
}
}
// VERWUNDBAR: Dateipfadübertragung aus nicht vertrauenswürdiger Quelle
public class VulnerableFileTransfer {
public void copyUserFile(String userFilePath, String destination) throws IOException {
// VERWUNDBAR: Benutzerkontrollierter Pfad an Dateisystemsphäre übertragen
Files.copy(Paths.get(userFilePath), Paths.get(destination));
// Pfadtraversierung: "../../../etc/passwd"
}
}
# VERWUNDBAR: Python fehlerhafte Ressourcentransfers
import pickle
import subprocess
import os
# VERWUNDBAR: Benutzereingabe an Subprocess-Sphäre
def process_file_vulnerable(filename):
# VERWUNDBAR: Benutzerdaten an Shell übertragen
os.system(f"cat {filename}") # Command Injection
# VERWUNDBAR: Pickle-Deserialisierung nicht vertrauenswürdiger Daten
def load_data_vulnerable(network_data):
# VERWUNDBAR: Netzwerkdaten an Objektsphäre übertragen
return pickle.loads(network_data) # Remote Code Execution
# VERWUNDBAR: Benutzereingabe an eval-Sphäre übertragen
def calculate_vulnerable(expression):
# VERWUNDBAR: Benutzer-Mathe an Code-Ausführung übertragen
return eval(expression) # Beliebiger Python-Code wird ausgeführt
# VERWUNDBAR: Sensible Daten an Template-Sphäre übertragen
from jinja2 import Template
def render_vulnerable(user_content):
# VERWUNDBAR: Benutzerinhalt an Template-Ausführungssphäre übertragen
template = Template(user_content)
return template.render() # SSTI - Server-Side Template Injection
# VERWUNDBAR: Datenbank-Credentials an Fehlermeldung übertragen
def connect_vulnerable():
try:
db = connect(f"postgresql://admin:secret@localhost/mydb")
except Exception as e:
# VERWUNDBAR: Sensible Daten an Fehlersphäre übertragen
raise Exception(f"Verbindung fehlgeschlagen: {e}") # Exponiert Credentials
# VERWUNDBAR: Benutzerdaten an Dateipfad-Sphäre übertragen
def read_file_vulnerable(user_path):
# VERWUNDBAR: Benutzerpfad direkt verwendet
with open(f"/var/data/{user_path}", 'r') as f:
return f.read() # Pfadtraversierung möglich
// VERWUNDBAR: JavaScript fehlerhafte Ressourcentransfers
const { exec } = require('child_process');
// VERWUNDBAR: Benutzereingabe an Shell-Sphäre übertragen
function runCommand(userInput) {
// VERWUNDBAR: Benutzerdaten mit Befehl vermischt
exec(`grep ${userInput} /var/log/app.log`, (err, stdout) => {
console.log(stdout);
});
}
// VERWUNDBAR: Benutzereingabe an eval-Sphäre übertragen
function calculate(expression) {
// VERWUNDBAR: Benutzer-Mathe als Code ausgeführt
return eval(expression);
}
// VERWUNDBAR: Nicht vertrauenswürdiges HTML an DOM-Sphäre übertragen
function displayMessage(userContent) {
// VERWUNDBAR: Benutzerinhalt an DOM übertragen (XSS)
document.getElementById('message').innerHTML = userContent;
}
// VERWUNDBAR: Sensible Daten an Client-Sphäre übertragen
app.get('/api/user/:id', (req, res) => {
const user = getUser(req.params.id);
// VERWUNDBAR: Internes Benutzerobjekt an Client gesendet
res.json(user); // Enthält passwordHash, internalNotes, etc.
});
// VERWUNDBAR: Benutzerdaten an Datenbankabfrage-Sphäre übertragen
app.get('/api/search', (req, res) => {
const query = req.query.q;
// VERWUNDBAR: Benutzereingabe in MongoDB-Abfrage
db.collection('users').find({ $where: `this.name == '${query}'` });
// NoSQL Injection
});
// VERWUNDBAR: Benutzerpfad an Dateisystem-Sphäre übertragen
app.get('/files/:filename', (req, res) => {
const filename = req.params.filename;
// VERWUNDBAR: Benutzerpfad direkt verwendet
res.sendFile(`/var/uploads/${filename}`);
});
// VERWUNDBAR: Cross-Origin-Datenübertragung
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
// VERWUNDBAR: Jeder Ursprung kann auf sensible Daten zugreifen
next();
});
// VERWUNDBAR: C fehlerhafte Ressourcentransfers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// VERWUNDBAR: Benutzereingabe an System-Befehls-Sphäre übertragen
void process_input_vulnerable(const char* user_input) {
char command[256];
// VERWUNDBAR: Benutzerdaten mit Befehl vermischt
sprintf(command, "echo %s", user_input);
system(command); // Command Injection
}
// VERWUNDBAR: Netzwerkdaten an Format-String-Sphäre übertragen
void log_message_vulnerable(const char* network_data) {
// VERWUNDBAR: Netzwerkdaten als Format-String verwendet
printf(network_data); // Format-String-Schwachstelle
}
// VERWUNDBAR: Benutzerpuffer an festen Puffer übertragen
void copy_data_vulnerable(const char* user_data) {
char buffer[64];
// VERWUNDBAR: Unbegrenzte Kopie aus Benutzersphäre
strcpy(buffer, user_data); // Buffer Overflow
}
// VERWUNDBAR: Netzwerkdaten an Speicheroperationen übertragen
void process_packet_vulnerable(const char* packet, int user_length) {
char buffer[1024];
// VERWUNDBAR: Benutzerkontrollierte Länge in Speicheroperation
memcpy(buffer, packet, user_length); // Overflow wenn length > 1024
}
// VERWUNDBAR: Benutzerindex an Array-Zugriffs-Sphäre übertragen
int get_item_vulnerable(int* array, int user_index) {
// VERWUNDBAR: Benutzerindex direkt verwendet
return array[user_index]; // Out-of-Bounds-Zugriff
}
Lösungscode
// SICHER: Ordnungsgemäßer Ressourcentransfer zwischen Sphären
import java.io.*;
import java.util.*;
public class SafeTransfer {
// SICHER: Benutzereingabe nicht direkt an Befehlssphäre übertragen
public void executeCommand(String userInput) {
// Option 1: Whitelist erlaubter Befehle
String[] allowed = {"list", "status", "help"};
if (Arrays.asList(allowed).contains(userInput)) {
ProcessBuilder pb = new ProcessBuilder("myapp", userInput);
pb.start();
}
// Option 2: ProcessBuilder mit Argumenten verwenden
ProcessBuilder pb = new ProcessBuilder("ls", "-la");
pb.directory(new File("/safe/directory"));
pb.start();
}
// SICHER: Sichere Deserialisierung verwenden
public Object deserializeFromNetwork(InputStream networkInput) {
// Option 1: JSON/XML mit Schema-Validierung verwenden
ObjectMapper mapper = new ObjectMapper();
// Sichere Standardwerte aktivieren
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
return mapper.readValue(networkInput, SafeDTO.class);
// Option 2: Wenn Java-Serialisierung erforderlich, Filter verwenden
// ObjectInputFilter filter = ...
// ois.setObjectInputFilter(filter);
}
// SICHER: Parametrisierte Abfrage
public void queryDatabase(String userInput, Connection conn) throws SQLException {
// SICHER: Parameter nie an SQL-Sphäre übertragen
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE name = ?");
stmt.setString(1, userInput);
stmt.executeQuery();
}
// SICHER: Vor Logging bereinigen
public void logUserAction(String username) {
// SICHER: Steuerzeichen vor Transfer zur Log-Sphäre entfernen
String sanitized = username.replaceAll("[\\r\\n]", "_");
logger.info("Benutzer eingeloggt: {}", sanitized); // Parametrisiertes Logging
}
// SICHER: Vor Übertragung an Client-Sphäre filtern
public void sendResponse(HttpServletResponse response, User user) throws IOException {
// SICHER: DTO nur mit öffentlichen Feldern erstellen
UserDTO dto = new UserDTO(user.getId(), user.getUsername(), user.getEmail());
// Kein Passwort-Hash, keine internen Daten
response.getWriter().write(objectMapper.writeValueAsString(dto));
}
}
// SICHER: Vor Dateioperationen validieren
public class SafeFileTransfer {
private static final Path SAFE_BASE = Paths.get("/var/uploads").toRealPath();
public void copyUserFile(String userFilePath, String destination) throws IOException {
// SICHER: Pfad validieren, dass er Basisverzeichnis nicht verlässt
Path sourcePath = SAFE_BASE.resolve(userFilePath).normalize();
Path destPath = SAFE_BASE.resolve(destination).normalize();
if (!sourcePath.startsWith(SAFE_BASE) || !destPath.startsWith(SAFE_BASE)) {
throw new SecurityException("Pfadtraversierung versucht");
}
Files.copy(sourcePath, destPath);
}
}
# SICHER: Python ordnungsgemäße Ressourcentransfers
import subprocess
import json
import os
from pathlib import Path
# SICHER: Listenargumente verwenden, nicht Shell-String
def process_file_safe(filename):
# SICHER: Argumente getrennt, nicht an Shell übertragen
allowed_chars = set('abcdefghijklmnopqrstuvwxyz0123456789._-')
if not all(c in allowed_chars for c in filename.lower()):
raise ValueError("Ungültiger Dateiname")
# Listenform verwenden - keine Shell-Interpolation
result = subprocess.run(['cat', filename], capture_output=True, text=True)
return result.stdout
# SICHER: JSON statt pickle verwenden
def load_data_safe(network_data):
# SICHER: JSON kann keinen Code ausführen
return json.loads(network_data)
# SICHER: Sichere Ausdrucksauswertung verwenden
import ast
import operator
SAFE_OPERATORS = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
}
def calculate_safe(expression):
# SICHER: Nur Mathe-Operationen parsen und auswerten
tree = ast.parse(expression, mode='eval')
def eval_node(node):
if isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.BinOp):
op = SAFE_OPERATORS.get(type(node.op))
if not op:
raise ValueError("Nicht unterstützte Operation")
return op(eval_node(node.left), eval_node(node.right))
else:
raise ValueError("Nicht unterstützter Ausdruck")
return eval_node(tree.body)
# SICHER: Autoescape für Templates verwenden
from jinja2 import Environment, select_autoescape
env = Environment(autoescape=select_autoescape())
def render_safe(template_name, **context):
# SICHER: Vordefiniertes Template laden, Benutzerdaten escapen
template = env.get_template(template_name)
return template.render(**context)
# SICHER: Sensible Daten nicht in Fehlern exponieren
def connect_safe(connection_string):
try:
return connect(connection_string)
except Exception as e:
# SICHER: Generischer Fehler, keine sensiblen Daten
raise Exception("Datenbankverbindung fehlgeschlagen") from None
# SICHER: Dateipfade validieren
UPLOAD_DIR = Path('/var/data').resolve()
def read_file_safe(user_path):
# SICHER: Pfad validieren, dass er im erlaubten Verzeichnis bleibt
full_path = (UPLOAD_DIR / user_path).resolve()
if not str(full_path).startswith(str(UPLOAD_DIR)):
raise ValueError("Ungültiger Pfad")
with open(full_path, 'r') as f:
return f.read()
// SICHER: JavaScript ordnungsgemäße Ressourcentransfers
const { spawn } = require('child_process');
const path = require('path');
// SICHER: spawn mit Array-Argumenten verwenden
function runCommand(userInput) {
// Whitelist erlaubter Suchbegriffe
const sanitized = userInput.replace(/[^a-zA-Z0-9]/g, '');
// SICHER: spawn mit Argumenten als Array verwenden
const grep = spawn('grep', [sanitized, '/var/log/app.log']);
grep.stdout.on('data', (data) => {
console.log(data.toString());
});
}
// SICHER: Sicheren Ausdrucksparser verwenden
const mathjs = require('mathjs');
function calculate(expression) {
// SICHER: mathjs führt keinen beliebigen Code aus
return mathjs.evaluate(expression);
}
// SICHER: textContent oder Bereinigung verwenden
function displayMessage(userContent) {
// SICHER: textContent führt kein HTML/JS aus
document.getElementById('message').textContent = userContent;
// Oder DOMPurify für HTML verwenden
const clean = DOMPurify.sanitize(userContent);
document.getElementById('message').innerHTML = clean;
}
// SICHER: Nur benötigte Felder an Client übertragen
app.get('/api/user/:id', (req, res) => {
const user = getUser(req.params.id);
// SICHER: Nur öffentliche Felder übertragen
res.json({
id: user.id,
username: user.username,
email: user.email
// Kein passwordHash, keine internalNotes
});
});
// SICHER: Parametrisierte MongoDB-Abfrage
app.get('/api/search', (req, res) => {
const query = req.query.q;
// SICHER: Benutzereingabe als Daten, nicht Code
db.collection('users').find({ name: query });
});
// SICHER: Dateipfad validieren
const UPLOAD_DIR = path.resolve('/var/uploads');
app.get('/files/:filename', (req, res) => {
const filename = req.params.filename;
const fullPath = path.resolve(UPLOAD_DIR, filename);
// SICHER: Verifizieren, dass Pfad im erlaubten Verzeichnis ist
if (!fullPath.startsWith(UPLOAD_DIR)) {
return res.status(403).send('Verboten');
}
res.sendFile(fullPath);
});
// SICHER: Restriktives CORS
const corsOptions = {
origin: ['https://myapp.com'],
methods: ['GET', 'POST'],
credentials: true
};
app.use(cors(corsOptions));
// SICHER: C ordnungsgemäße Ressourcentransfers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// SICHER: Benutzereingabe nicht an system() übertragen
void process_input_safe(const char* user_input) {
// Option 1: Whitelist
const char* allowed[] = {"list", "status", NULL};
int valid = 0;
for (int i = 0; allowed[i]; i++) {
if (strcmp(user_input, allowed[i]) == 0) {
valid = 1;
break;
}
}
// Option 2: execve mit Argumenten verwenden
if (valid) {
pid_t pid = fork();
if (pid == 0) {
char* args[] = {"myapp", (char*)user_input, NULL};
execve("/usr/bin/myapp", args, NULL);
exit(1);
}
}
}
// SICHER: Netzwerkdaten nicht als Format-String verwenden
void log_message_safe(const char* network_data) {
// SICHER: Daten ist Argument, nicht Format
printf("%s", network_data);
}
// SICHER: Begrenzte Kopie
void copy_data_safe(const char* user_data, size_t user_len) {
char buffer[64];
// SICHER: Größe begrenzen
size_t copy_len = user_len < sizeof(buffer) - 1 ? user_len : sizeof(buffer) - 1;
memcpy(buffer, user_data, copy_len);
buffer[copy_len] = '\0';
}
// SICHER: Vor Speicheroperation validieren
void process_packet_safe(const char* packet, int user_length) {
char buffer[1024];
// SICHER: Länge vor Übertragung validieren
if (user_length > 0 && user_length <= sizeof(buffer)) {
memcpy(buffer, packet, user_length);
}
}
// SICHER: Grenzenprüfung vor Array-Zugriff
int get_item_safe(int* array, size_t array_size, int user_index) {
// SICHER: Index vor Übertragung zum Array-Zugriff validieren
if (user_index >= 0 && (size_t)user_index < array_size) {
return array[user_index];
}
return -1; // Fehlerwert
}
Ausgenutzt in der Praxis
Deserialisierungsangriffe
Java/Python pickle RCE über nicht vertrauenswürdige Deserialisierung.
Command Injection
Benutzereingabe an Shell übertragen, verursacht Systemkompromittierung.
SQL/NoSQL Injection
Benutzerdaten unsachgemäß an Datenbankabfragen übertragen.
Werkzeuge zum Testen/Ausnutzen
-
Burp Suite für Injection-Tests.
-
ysoserial für Java-Deserialisierung.
-
SQLMap für Datenbank-Injection.
CVE-Beispiele
-
CVE-2015-4852: Java-Deserialisierung (WebLogic).
-
CVE-2017-5638: Struts2 OGNL-Injection.
Referenzen
-
MITRE. "CWE-669: Incorrect Resource Transfer Between Spheres." https://cwe.mitre.org/data/definitions/669.html
-
OWASP Injection-Prävention.