Unsachgemäße Einschränkung des Stromverbrauchs

Beschreibung

Unsachgemäße Einschränkung des Stromverbrauchs tritt auf, wenn Software in Umgebungen betrieben wird, in denen Strom eine begrenzte Ressource ist, die nicht automatisch aufgefüllt werden kann (wie batteriebetriebene Geräte), aber die Strommenge, die der Betrieb verbraucht, nicht ordnungsgemäß einschränkt. Diese Schwachstelle ist besonders relevant für mobile Geräte, eingebettete Systeme, IoT-Geräte und jede batteriebetriebene Ausrüstung. Angreifer können diese Schwäche ausnutzen, indem sie Operationen auslösen, die übermäßigen Stromverbrauch durch Komponenten wie CPU-intensive Berechnungen, Display-Helligkeit, GPS-Empfänger, Funkmodule, Festplatten-I/O, Soundsysteme, Kameras oder USB-Schnittstellen verursachen.

Risiko

Die Ausnutzung dieser Schwachstelle kann zu einem vollständigen Denial-of-Service durch Entleerung der Gerätebatterie führen. Bei mobilen Geräten kann dies Telefone in kritischen Situationen unbrauchbar machen. In IoT- und eingebetteten Systemen kann Stromerschöpfung Sicherheitssysteme, medizinische Geräte oder industrielle Steuerungen deaktivieren. Kontinuierliche Stromverbrauchsangriffe können die Batterielebensdauer durch übermäßige Ladezyklen verkürzen. In sicherheitskritischen Systemen kann unerwarteter Stromverlust schwerwiegende Folgen haben. Der Angriff kann persistent und schwer zu erkennen sein, da der Stromverbrauch eher mit normalem Betrieb als mit bösartiger Aktivität zusammenzuhängen scheint.

Lösung

Implementieren Sie Stromverbrauchsbudgets und -überwachung für alle Operationen. Begrenzen Sie die Häufigkeit stromintensiver Operationen. Verwenden Sie stromeffiziente Algorithmen und Hardware-Funktionen wie Schlafmodi. Implementieren Sie Rate-Limiting für Operationen, die hohen Stromverbrauch auslösen. Überwachen und warnen Sie bei ungewöhnlichen Stromverbrauchsmustern. Entwerfen Sie Anwendungen, um niedrige Stromzustände elegant zu handhaben. Validieren Sie Eingaben, die stromverbrauchende Operationen steuern, um Missbrauch zu verhindern. Erwägen Sie die Implementierung von Stromverbrauchslimits pro Zeitraum. Nutzen Sie Hardware-Strommanagement-Funktionen effektiv. Für mobile Apps folgen Sie den Plattformrichtlinien für Hintergrundverarbeitung und Wake Locks.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

DoS: Ressourcenverbrauch - Übermäßiger Stromverbrauch entleert Batterien und führt dazu, dass Geräte herunterfahren und nicht mehr verfügbar sind.
VerfügbarkeitBereich: Verfügbarkeit

DoS: Absturz/Beenden/Neustart - Stromerschöpfung kann dazu führen, dass Anwendungen und ganze Geräte aufhören zu funktionieren.

Beispielcode

Anfälliger Code

// Anfällig: Android-App mit uneingeschränkter GPS-Nutzung
public class VulnerableLocationService extends Service {

    private LocationManager locationManager;

    @Override
    public void onCreate() {
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    }

    public void startTracking(int intervalMs) {
        // Anfällig: Keine Validierung des Intervalls, GPS immer an
        locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            intervalMs,  // Angreifer kann 0 für konstante Updates setzen
            0,
            locationListener
        );

        // Anfällig: Keine Berücksichtigung des Stromverbrauchs, GPS entleert Batterie schnell
    }
}

// Angriff: Tracking mit intervalMs=0 starten, um Batterie schnell zu entleeren
// Anfällig: Uneingeschränkte Wake-Lock-Nutzung
public class VulnerableBackgroundTask {

    private PowerManager.WakeLock wakeLock;

    public void startTask(Context context) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

        // Anfällig: Wake Lock ohne Timeout erwerben
        wakeLock = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK,
            "MyApp::BackgroundTask"
        );
        wakeLock.acquire();  // Kein Timeout - hält CPU unbegrenzt laufen

        // Wenn Task nie abschließt oder abstürzt, entleert sich die Batterie
    }

    // Anfällig: Wird möglicherweise nie aufgerufen, wenn Task fehlschlägt
    public void stopTask() {
        if (wakeLock != null && wakeLock.isHeld()) {
            wakeLock.release();
        }
    }
}
// Anfällig: iOS-App mit konstantem Netzwerk-Polling
class VulnerableNetworkPoller {

    var timer: Timer?

    func startPolling(intervalSeconds: Double) {
        // Anfällig: Kein Mindestintervall, keine Stromzuständsprüfung
        timer = Timer.scheduledTimer(
            withTimeInterval: intervalSeconds,  // Könnte 0.001 sein
            repeats: true
        ) { _ in
            self.fetchData()
        }
    }

    func fetchData() {
        // Jede Netzwerkanfrage verhindert Schlaf und nutzt Funk
        URLSession.shared.dataTask(with: url) { data, response, error in
            // Daten verarbeiten
        }.resume()
    }
}

// Angriff: Intervall auf 0.001 für 1000 Anfragen/Sekunde setzen
// Anfällig: Eingebettetes System ohne Strommanagement
void vulnerable_sensor_read(void) {
    // Anfällig: Sensor immer an, keine Schlafmodi
    while (1) {
        // Konstantes Sensorlesen ohne Verzögerung
        int value = read_sensor();
        process_data(value);

        // Kein Schlaf, kein Strommanagement
        // CPU und Sensor immer auf voller Leistung
    }
}

Korrigierter Code

// Korrigiert: Android-App mit strombewusster GPS-Nutzung
public class FixedLocationService extends Service {

    private LocationManager locationManager;
    private static final long MIN_UPDATE_INTERVAL_MS = 10000;  // 10 Sekunden Minimum
    private static final long MAX_ACTIVE_TIME_MS = 300000;  // 5 Minuten Maximum
    private Handler timeoutHandler = new Handler(Looper.getMainLooper());

    @Override
    public void onCreate() {
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    }

    public void startTracking(long requestedIntervalMs) {
        // Korrigiert: Mindestintervall erzwingen
        long interval = Math.max(requestedIntervalMs, MIN_UPDATE_INTERVAL_MS);

        // Korrigiert: Batteriestand vor Start prüfen
        if (getBatteryLevel() < 20) {
            Log.w(TAG, "Batterie zu niedrig für GPS-Tracking");
            return;
        }

        locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            interval,
            10,  // 10 Meter Mindestdistanz
            locationListener
        );

        // Korrigiert: Automatischer Timeout, um unbegrenzte GPS-Nutzung zu verhindern
        timeoutHandler.postDelayed(this::stopTracking, MAX_ACTIVE_TIME_MS);
    }

    public void stopTracking() {
        locationManager.removeUpdates(locationListener);
        timeoutHandler.removeCallbacksAndMessages(null);
    }

    private int getBatteryLevel() {
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent batteryStatus = registerReceiver(null, filter);
        int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        return (int) (level * 100 / (float) scale);
    }
}
// Korrigiert: Sichere Wake-Lock-Nutzung mit Timeout
public class FixedBackgroundTask {

    private static final long MAX_WAKE_LOCK_MS = 60000;  // 1 Minute Maximum

    public void startTask(Context context) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

        PowerManager.WakeLock wakeLock = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK,
            "MyApp::BackgroundTask"
        );

        // Korrigiert: Mit Timeout erwerben - wird nach Timeout automatisch freigegeben
        wakeLock.acquire(MAX_WAKE_LOCK_MS);

        try {
            performTask();
        } finally {
            // Korrigiert: Immer im finally-Block freigeben
            if (wakeLock.isHeld()) {
                wakeLock.release();
            }
        }
    }
}

// Besser: WorkManager für Hintergrund-Tasks verwenden
public class FixedWorkManager {

    public void scheduleTask(Context context) {
        // WorkManager handhabt Strommanagement automatisch
        Constraints constraints = new Constraints.Builder()
            .setRequiresBatteryNotLow(true)  // Nur ausführen, wenn Batterie OK
            .build();

        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
            .setConstraints(constraints)
            .build();

        WorkManager.getInstance(context).enqueue(workRequest);
    }
}
// Korrigiert: iOS-App mit strombewusstem Polling
class FixedNetworkPoller {

    var timer: Timer?
    private let minimumInterval: TimeInterval = 30  // 30 Sekunden Minimum
    private let maxPollingDuration: TimeInterval = 300  // 5 Minuten Maximum
    private var startTime: Date?

    func startPolling(requestedInterval: TimeInterval) {
        // Korrigiert: Mindestintervall erzwingen
        let interval = max(requestedInterval, minimumInterval)

        // Korrigiert: Batteriestatus prüfen
        UIDevice.current.isBatteryMonitoringEnabled = true
        if UIDevice.current.batteryLevel < 0.2 && UIDevice.current.batteryState != .charging {
            print("Batterie zu niedrig für Polling")
            return
        }

        startTime = Date()

        timer = Timer.scheduledTimer(
            withTimeInterval: interval,
            repeats: true
        ) { [weak self] timer in
            guard let self = self else {
                timer.invalidate()
                return
            }

            // Korrigiert: Prüfen, ob maximale Dauer überschritten
            if let start = self.startTime,
               Date().timeIntervalSince(start) > self.maxPollingDuration {
                self.stopPolling()
                return
            }

            self.fetchData()
        }
    }

    func stopPolling() {
        timer?.invalidate()
        timer = nil
    }
}
// Korrigiert: Eingebettetes System mit Strommanagement
#include <power_management.h>

void fixed_sensor_read(void) {
    uint32_t last_read_time = 0;
    const uint32_t MIN_INTERVAL_MS = 1000;  // 1 Sekunde Minimum

    while (1) {
        uint32_t current_time = get_system_time_ms();

        // Korrigiert: Rate-Limiting
        if (current_time - last_read_time < MIN_INTERVAL_MS) {
            // In Niedrigstrommodus wechseln während des Wartens
            enter_sleep_mode(MIN_INTERVAL_MS - (current_time - last_read_time));
            continue;
        }

        last_read_time = current_time;

        // Sensor nur bei Bedarf aktivieren
        sensor_power_on();
        int value = read_sensor();
        sensor_power_off();  // Sensor nach Lesen deaktivieren

        process_data(value);

        // In Niedrigstrommodus zwischen Lesevorgängen wechseln
        enter_sleep_mode(MIN_INTERVAL_MS);
    }
}

Verwandte CWEs

  • CWE-400: Uncontrolled Resource Consumption (Eltern)
  • CWE-770: Allocation of Resources Without Limits or Throttling (verwandt)
  • CWE-399: Resource Management Errors (Kategorie)

Referenzen

  1. MITRE Corporation. "CWE-920: Improper Restriction of Power Consumption." https://cwe.mitre.org/data/definitions/920.html
  2. Android Developers. "Optimize for battery life." https://developer.android.com/training/monitoring-device-state/battery-monitoring
  3. Apple Developer Documentation. "Energy Efficiency Guide for iOS Apps."