Aufrufbares Kontrollelement mit übermäßigen Datei- oder Datenzugriffsoperationen
Beschreibung
Aufrufbares Kontrollelement mit übermäßigen Datei- oder Datenzugriffsoperationen tritt auf, wenn eine Funktion oder Methode zu viele Operationen mit Datei- oder Datenmanagerressourcen durchführt. CISQ empfiehlt einen maximalen Schwellenwert von 7 Operationen auf demselben Datenmanager oder derselben Datei innerhalb eines einzelnen aufrufbaren Kontrollelements. Wenn eine einzelne Funktion viele Datei- oder Datenbankoperationen durchführt, wird sie schwer zu verstehen, zu warten und zu testen. Diese Komplexität erhöht die Wahrscheinlichkeit von Fehlern, einschließlich Sicherheitsschwachstellen.
Risiko
Übermäßige Datei- oder Datenoperationen in einer einzelnen Funktion haben Sicherheitsimplikationen. Komplexe Funktionen mit vielen I/O-Operationen sind schwerer auf Sicherheitsprobleme zu prüfen. Ressourcenverwaltung wird fehleranfällig, was das Risiko von Lecks erhöht. Fehlerbehandlung für mehrere Operationen ist komplex und oft unvollständig. Die Funktion verletzt wahrscheinlich die einzelne Verantwortlichkeit und mischt Belange, die getrennt werden sollten. Leistungsprobleme durch viele Operationen können zu Denial-of-Service führen. Transaktionsgrenzen werden bei vielen Datenbankoperationen unklar.
Lösung
Wenden Sie das Single-Responsibility-Prinzip an - jede Funktion sollte eine Sache tun. Extrahieren Sie verwandte Operationen in separate, fokussierte Methoden. Verwenden Sie das Repository-Pattern, um Datenzugriff zu kapseln. Fassen Sie mehrere Datenbankoperationen wenn möglich zusammen. Verwenden Sie Transaktionen angemessen für verwandte Operationen. Erwägen Sie das Unit-of-Work-Pattern für komplexe Datenoperationen. Implementieren Sie ordnungsgemäße Fehlerbehandlung und Ressourcenverwaltung. Verwenden Sie statische Analysetools, um Funktionen mit übermäßigen Operationen zu erkennen. Refaktorisieren Sie große Funktionen in kleinere, testbare Einheiten.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Andere | Bereich: Ändere Reduzierte Wartbarkeit - Funktionen mit vielen Operationen sind schwer zu verstehen und zu modifizieren. |
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Ressourcenverbrauch - Mehrere Operationen erhöhen Ressourcennutzung und Potenzial für Lecks. |
| Andere | Bereich: Ändere Qualitätsverschlechterung - Komplexität erhöht Fehlerwahrscheinlichkeit einschließlich Sicherheitsproblemen. |
Beispielcode
Anfälliger Code
// Anfällig: Einzelne Methode mit übermäßigen Datenoperationen (15+ Operationen)
public class VulnerableReportGenerator {
public Report generateComprehensiveReport(Long userId) throws Exception {
Connection conn = dataSource.getConnection();
try {
// Operation 1: Benutzer abrufen
PreparedStatement ps1 = conn.prepareStatement(
"SELECT * FROM users WHERE id = ?");
ps1.setLong(1, userId);
ResultSet rs1 = ps1.executeQuery();
User user = mapUser(rs1);
// Operation 2: Benutzerprofil abrufen
PreparedStatement ps2 = conn.prepareStatement(
"SELECT * FROM profiles WHERE user_id = ?");
ps2.setLong(1, userId);
ResultSet rs2 = ps2.executeQuery();
Profile profile = mapProfile(rs2);
// Operation 3: Benutzereinstellungen abrufen
PreparedStatement ps3 = conn.prepareStatement(
"SELECT * FROM settings WHERE user_id = ?");
ps3.setLong(1, userId);
ResultSet rs3 = ps3.executeQuery();
Settings settings = mapSettings(rs3);
// Operation 4: Benutzerbestellungen abrufen
PreparedStatement ps4 = conn.prepareStatement(
"SELECT * FROM orders WHERE user_id = ?");
ps4.setLong(1, userId);
ResultSet rs4 = ps4.executeQuery();
List<Order> orders = mapOrders(rs4);
// Operation 5: Benutzerzahlungen abrufen
PreparedStatement ps5 = conn.prepareStatement(
"SELECT * FROM payments WHERE user_id = ?");
ps5.setLong(1, userId);
ResultSet rs5 = ps5.executeQuery();
List<Payment> payments = mapPayments(rs5);
// Operation 6: Benutzeraktivitäten abrufen
PreparedStatement ps6 = conn.prepareStatement(
"SELECT * FROM activities WHERE user_id = ?");
ps6.setLong(1, userId);
ResultSet rs6 = ps6.executeQuery();
List<Activity> activities = mapActivities(rs6);
// Operationen 7-10: Verwandte Daten für Bestellungen abrufen
for (Order order : orders) {
PreparedStatement psItems = conn.prepareStatement(
"SELECT * FROM order_items WHERE order_id = ?");
psItems.setLong(1, order.getId());
ResultSet rsItems = psItems.executeQuery();
order.setItems(mapOrderItems(rsItems));
}
// Operationen 11-15: Zusätzliche Abfragen
// ... weitere Datenbankoperationen ...
// Anfällig: 15+ Datenbankoperationen in einzelner Methode
// - Schwer zu verstehen und zu warten
// - Ressourcenverwaltung ist komplex
// - Fehlerbehandlung ist unvollständig
// - Keine Klarheit über Transaktionsgrenzen
return new Report(user, profile, settings, orders, payments, activities);
} finally {
conn.close(); // Schließt möglicherweise nicht alle Statements/ResultSets
}
}
}
# Anfällig: Funktion mit übermäßigen Dateioperationen
class VulnerableFileProcessor:
def process_all_files(self, input_dir: str, output_dir: str) -> dict:
"""Verarbeitet alle Dateien - zu viele Dateioperationen in einer Funktion."""
results = {}
# Operation 1: Konfigurationsdatei lesen
with open(f"{input_dir}/config.json") as f:
config = json.load(f)
# Operation 2: Eingabedatendatei lesen
with open(f"{input_dir}/data.csv") as f:
data = csv.reader(f)
rows = list(data)
# Operation 3: Referenzdaten lesen
with open(f"{input_dir}/reference.json") as f:
reference = json.load(f)
# Operation 4: Mapping-Datei lesen
with open(f"{input_dir}/mapping.yaml") as f:
mapping = yaml.safe_load(f)
# Operation 5: Template lesen
with open(f"{input_dir}/template.html") as f:
template = f.read()
# Daten mit allen geladenen Dateien verarbeiten...
processed = self._process(rows, reference, mapping, config)
# Operation 6: Hauptausgabe schreiben
with open(f"{output_dir}/output.json", 'w') as f:
json.dump(processed, f)
# Operation 7: Log-Datei schreiben
with open(f"{output_dir}/process.log", 'w') as f:
f.write(self._generate_log())
# Operation 8: Bericht schreiben
with open(f"{output_dir}/report.html", 'w') as f:
f.write(self._render_template(template, processed))
# Operationen 9-12: Individuelle Ausgabedateien schreiben
for item in processed['items']:
filename = f"{output_dir}/item_{item['id']}.json"
with open(filename, 'w') as f:
json.dump(item, f)
# Operation 13: An Zusammenfassungsdatei anhängen
with open(f"{output_dir}/summary.csv", 'a') as f:
writer = csv.writer(f)
writer.writerow([datetime.now(), len(processed['items'])])
# Anfällig: 13+ Dateioperationen in einzelner Funktion
# - Komplexe Fehlerbehandlung erforderlich
# - Teilfehler hinterlassen System in inkonsistentem Zustand
# - Schwierig, individuelle Operationen zu testen
return results
Korrigierter Code
// Korrigiert: Separate Methoden mit fokussierten Verantwortlichkeiten
public class FixedReportGenerator {
private final UserRepository userRepository;
private final ProfileRepository profileRepository;
private final OrderRepository orderRepository;
private final PaymentRepository paymentRepository;
private final ActivityRepository activityRepository;
public FixedReportGenerator(
UserRepository userRepository,
ProfileRepository profileRepository,
OrderRepository orderRepository,
PaymentRepository paymentRepository,
ActivityRepository activityRepository) {
this.userRepository = userRepository;
this.profileRepository = profileRepository;
this.orderRepository = orderRepository;
this.paymentRepository = paymentRepository;
this.activityRepository = activityRepository;
}
// Korrigiert: Hauptmethode orchestriert, führt Datenzugriff nicht direkt durch
public Report generateComprehensiveReport(Long userId) {
// Jeder Aufruf geht an eine fokussierte Repository-Methode
User user = userRepository.findWithProfile(userId);
Settings settings = userRepository.findSettings(userId);
List<Order> orders = orderRepository.findWithItemsByUserId(userId);
List<Payment> payments = paymentRepository.findByUserId(userId);
List<Activity> activities = activityRepository.findByUserId(userId);
return new Report(user, user.getProfile(), settings, orders, payments, activities);
}
}
// Korrigiert: Fokussierte Repository-Methoden
@Repository
public class UserRepository {
@PersistenceContext
private EntityManager em;
// Korrigiert: Einzelne Abfrage mit JOIN FETCH
public User findWithProfile(Long userId) {
return em.createQuery(
"SELECT u FROM User u LEFT JOIN FETCH u.profile WHERE u.id = :id",
User.class)
.setParameter("id", userId)
.getSingleResult();
}
// Korrigiert: Separate fokussierte Methode
public Settings findSettings(Long userId) {
return em.createQuery(
"SELECT s FROM Settings s WHERE s.userId = :userId",
Settings.class)
.setParameter("userId", userId)
.getSingleResult();
}
}
@Repository
public class OrderRepository {
@PersistenceContext
private EntityManager em;
// Korrigiert: Einzelne Abfrage holt Bestellungen mit Elementen
public List<Order> findWithItemsByUserId(Long userId) {
return em.createQuery(
"SELECT DISTINCT o FROM Order o " +
"LEFT JOIN FETCH o.items " +
"WHERE o.userId = :userId",
Order.class)
.setParameter("userId", userId)
.getResultList();
}
}
// Alternative: Batch-Loading für bessere Leistung verwenden
@Repository
public class OptimizedOrderRepository {
public List<Order> findWithItemsByUserId(Long userId) {
// Abfrage 1: Bestellungen abrufen
List<Order> orders = em.createQuery(
"SELECT o FROM Order o WHERE o.userId = :userId", Order.class)
.setParameter("userId", userId)
.getResultList();
if (!orders.isEmpty()) {
List<Long> orderIds = orders.stream()
.map(Order::getId)
.collect(toList());
// Abfrage 2: Batch-Laden von Elementen für alle Bestellungen
Map<Long, List<OrderItem>> itemsByOrderId = em.createQuery(
"SELECT i FROM OrderItem i WHERE i.orderId IN :orderIds",
OrderItem.class)
.setParameter("orderIds", orderIds)
.getResultStream()
.collect(groupingBy(OrderItem::getOrderId));
// Elemente Bestellungen zuweisen
orders.forEach(o ->
o.setItems(itemsByOrderId.getOrDefault(o.getId(), emptyList())));
}
return orders;
}
}
# Korrigiert: Separate Klassen und Methoden für Dateioperationen
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, List, Any
@dataclass
class ProcessingConfig:
config: Dict
reference: Dict
mapping: Dict
template: str
class ConfigLoader:
"""Fokussierte Klasse zum Laden von Konfigurationsdateien."""
def __init__(self, input_dir: Path):
self._input_dir = input_dir
def load_config(self) -> ProcessingConfig:
"""Lädt alle Konfiguration in einzelner fokussierter Methode."""
return ProcessingConfig(
config=self._load_json('config.json'),
reference=self._load_json('reference.json'),
mapping=self._load_yaml('mapping.yaml'),
template=self._load_text('template.html')
)
def _load_json(self, filename: str) -> Dict:
with open(self._input_dir / filename) as f:
return json.load(f)
def _load_yaml(self, filename: str) -> Dict:
with open(self._input_dir / filename) as f:
return yaml.safe_load(f)
def _load_text(self, filename: str) -> str:
return (self._input_dir / filename).read_text()
class DataReader:
"""Fokussierte Klasse zum Lesen von Eingabedaten."""
def __init__(self, input_dir: Path):
self._input_dir = input_dir
def read_data(self) -> List[List[str]]:
with open(self._input_dir / 'data.csv') as f:
return list(csv.reader(f))
class ReportWriter:
"""Fokussierte Klasse zum Schreiben von Ausgabedateien."""
def __init__(self, output_dir: Path):
self._output_dir = output_dir
self._output_dir.mkdir(parents=True, exist_ok=True)
def write_main_output(self, processed: Dict) -> None:
with open(self._output_dir / 'output.json', 'w') as f:
json.dump(processed, f)
def write_report(self, template: str, data: Dict) -> None:
rendered = self._render_template(template, data)
with open(self._output_dir / 'report.html', 'w') as f:
f.write(rendered)
def write_items(self, items: List[Dict]) -> None:
for item in items:
filename = self._output_dir / f"item_{item['id']}.json"
with open(filename, 'w') as f:
json.dump(item, f)
class LogWriter:
"""Fokussierte Klasse für Protokollierung."""
def __init__(self, output_dir: Path):
self._log_file = output_dir / 'process.log'
self._summary_file = output_dir / 'summary.csv'
def write_log(self, log_content: str) -> None:
with open(self._log_file, 'w') as f:
f.write(log_content)
def append_summary(self, item_count: int) -> None:
with open(self._summary_file, 'a') as f:
writer = csv.writer(f)
writer.writerow([datetime.now().isoformat(), item_count])
class FileProcessor:
"""Hauptprozessor, der fokussierte Komponenten orchestriert."""
def __init__(self, input_dir: str, output_dir: str):
self._input_path = Path(input_dir)
self._output_path = Path(output_dir)
# Korrigiert: Jede Komponente behandelt spezifische Operationen
self._config_loader = ConfigLoader(self._input_path)
self._data_reader = DataReader(self._input_path)
self._report_writer = ReportWriter(self._output_path)
self._log_writer = LogWriter(self._output_path)
def process_all_files(self) -> Dict:
"""Korrigiert: Orchestriert Komponenten, jede mit fokussierter Verantwortlichkeit."""
# Konfiguration laden (2-3 Operationen in fokussierter Klasse)
config = self._config_loader.load_config()
# Daten lesen (1 Operation)
rows = self._data_reader.read_data()
# Daten verarbeiten (keine I/O)
processed = self._process_data(rows, config)
# Ausgaben schreiben (Operationen in fokussierten Klassen)
self._report_writer.write_main_output(processed)
self._report_writer.write_report(config.template, processed)
self._report_writer.write_items(processed.get('items', []))
# Logs schreiben
self._log_writer.write_log(self._generate_log())
self._log_writer.append_summary(len(processed.get('items', [])))
return processed
def _process_data(self, rows: List, config: ProcessingConfig) -> Dict:
"""Reine Verarbeitungslogik - keine I/O-Operationen."""
# Daten mit Konfiguration verarbeiten
return {'items': []}
def _generate_log(self) -> str:
return f"Verarbeitet am {datetime.now()}"
CVE-Beispiele
Diese CWE ist für direkte CVE-Zuordnung als VERBOTEN markiert, da sie ein Codequalitäts-/Wartbarkeitsproblem und keine direkte Sicherheitsschwachstelle darstellt.
Verwandte CWEs
- CWE-405: Asymmetric Resource Consumption (Eltern)
- CWE-1060: Excessive Number of Inefficient Server-Side Data Accesses (verwandt)
- CWE-1073: Non-SQL Invokable Control Element with Excessive Data Accesses (verwandt)
Referenzen
-
MITRE Corporation. "CWE-1084: Invokable Control Element with Excessive File or Data Access Operations." https://cwe.mitre.org/data/definitions/1084.html
-
CISQ. "Automated Source Code Quality Measures."
-
Martin, Robert C. "Clean Code" - Single Responsibility Principle.