Secure Coding: CWE-377 – Unsichere temporäre Dateien und wie man sie vermeidet

Die Common Weakness Enumeration CWE-377 beschreibt eine – vermeidbare – Schwachstelle durch unsicheres Erstellen und Verwalten temporärer Dateien.

In Pocket speichern vorlesen Druckansicht 33 Kommentare lesen
Halber Mensch vor einer Sanduhr mit Uhr darin

(Bild: erstellt mit Chat-GPT / DALL-E)

Lesezeit: 12 Min.
Von
  • Sven Ruppert
Inhaltsverzeichnis

In der Praxis nutzen Entwicklerinnen und Entwickler temporäre Dateien häufig dazu, um Daten während der Ausführung einer Anwendung vorübergehend zu speichern. Diese Daten sollen entweder direkt verarbeitet oder auch an andere Teile eines Programms weitergegeben werden – und sie können vertrauliche Informationen enthalten. Werden diese temporären Dateien jedoch nicht sicher verwaltet, können sie Schwachstellen öffnen, die die Vertraulichkeit, Integrität oder Verfügbarkeit der Anwendung gefährden. Die Common Weakness Enumeration CWE-377 beschreibt eine solche Schwachstelle im Zusammenhang mit der unsicheren Erstellung und Verwaltung temporärer Dateien im Detail.

Secure Coding – Sven Ruppert

Seit 1996 programmiert Sven Java in Industrieprojekten und seit über 15 Jahren weltweit in Branchen wie Automobil, Raumfahrt, Versicherungen, Banken, UN und Weltbank. Seit über 10 Jahren ist er von Amerika bis nach Neuseeland als Speaker auf Konferenzen und Community Events, arbeitete als Developer Advocate für JFrog und Vaadin und schreibt regelmäßig Beiträge für IT-Zeitschriften und Technologieportale. Neben seinem Hauptthema Core Java beschäftigt er sich mit TDD und Secure Coding Practices.

Die Bezeichnung "unsichere temporäre Datei" bezieht sich laut CWE-377 auf eine Sicherheitslücke, die auftritt, wenn ein Programm eine temporäre Datei auf eine unsichere Weise erstellt. Angreifer können diese Schwachstelle ausnutzen, um verschiedene böswillige Aktivitäten durchzuführen, darunter Datenmanipulation, unbefugten Datenzugriff oder Denial of Service (DoS). Beim Erstellen unsicherer temporärer Dateien treten typischerweise folgende Probleme auf:

Vorhersehbare Dateinamen: Wenn temporäre Dateien vorhersehbare Namen haben, können Angreifer diese leicht erraten und sich Zugriff verschaffen, um den Dateiinhalt zu lesen oder zu ändern.

Unsichere Dateiberechtigungen: Falsche Berechtigungen können dazu führen, dass nicht autorisierte Benutzer auf temporäre Dateien zugreifen oder diese ändern.

Race Condition: Eine Race Condition (Wettlaufsituation) vom Typ Time-of-Check-to-Time-of-Use (TOCTOU) kann auftreten, wenn ein Angreifer einer Anwendung zuvorkommt und eine Datei mit demselben Namen erstellt, wie die Anwendung sie generieren wollte.

In Java verwenden Entwickler temporäre Dateien häufig für verschiedene Zwecke, beispielsweise zum Zwischenspeichern, Verarbeiten von vorläufigen Daten oder Speichern temporärer Ergebnisse. Java bietet mehrere Möglichkeiten zum Erstellen temporärer Dateien, darunter die Methode File.createTempFile(), die eine temporäre Datei mit einem eindeutigen Namen im Standardverzeichnis für temporäre Dateien generiert.

Eine unsachgemäße Verwendung dieser APIs kann dennoch zu den in CWE-377 beschriebenen Risiken führen, wie die nachfolgenden Codebeispiele zeigen:

import java.io.File;
import java.io.IOException;

public class InsecureTempFileExample {
    public static void main(String[] args) throws IOException {
        File tempFile = new File("/tmp/tempfile.txt");
        tempFile.createNewFile();
        System.out.println("Temporary file created at: " + tempFile.getAbsolutePath());
    }
}

Der Code in diesem Beispiel erstellt eine temporäre Datei mit einem fest codierten Dateinamen (tempfile.txt) im Verzeichnis /tmp. Dieser Ansatz ist aus mehreren Gründen unsicher: Der Dateiname ist vorhersehbar, sodass ein Angreifer vor der Anwendung eine Datei mit demselben Namen erstellen kann, was zu der genannten TOCTOU-Race-Condition führt. Die Datei wird ohne Kontrolle über Dateiberechtigungen erstellt, wodurch möglicherweise auch vertrauliche Daten offengelegt werden.

Mögliche Auswirkungen

CWE-377 kann je nach Verwendung der temporären Datei und der Sensibilität der darin enthaltenen Daten schwerwiegende Folgen haben. Zu den möglichen Auswirkungen gehören:

Offenlegen von Informationen: Kann ein Angreifer den Namen einer temporären Datei vorhersagen, kann er möglicherweise auch deren Inhalt lesen, wenn die Datei nicht ausreichend geschützt ist. Dies führt dann dazu, dass sensible Informationen wie Passwörter, Token oder persönliche Daten preisgegeben werden.

Datenmanipulation: Ein Angreifer könnte eine temporäre Datei erstellen oder ändern, bevor die Anwendung sie verwendet, was Datenbeschädigung oder unbefugte Änderungen nach sich ziehen kann. Potenzielle Folgen davon wären fehlerhaftes Anwendungsverhalten oder die Einführung schädlicher Daten in das System.

Denial of Service (DoS): Durch das präventive Erstellen temporärer Dateien mit den Namen, die eine Anwendung voraussichtlich verwenden wird, kann ein Angreifer gezielt den ordnungsgemäßen Betrieb einer Anwendung verhindern und einen Denial of Service auslösen.

Abhilfemaßnahmen

Um CWE-377 zu verhindern, müssen Entwickler bei der Arbeit mit temporären Dateien sichere Programmierpraktiken einhalten. Im Folgenden zeige ich mehrere Strategien für die sichere Erstellung und Verwaltung temporärer Dateien in Java:

1. Verwende File.createTempFile() ordnungsgemäß

Die Methode File.createTempFile() generiert einen eindeutigen aber zufälligen temporären Dateinamen und verringert so das Risiko vorhersehbarer Dateinamen. Sie erlaubt es Entwicklern auch, ein Verzeichnis für die Datei anzugeben, obwohl standardmäßig das Temp-Verzeichnis des Systems verwendet wird.

import java.io.File;
import java.io.IOException;

public class SecureTempFileExample {
    public static void main(String[] args) throws IOException {
        File tempFile = File.createTempFile("tempfile_", ".tmp");
        tempFile.deleteOnExit(); // Ensures the file is deleted when the JVM exits
        System.out.println("Temporary file created at: " + tempFile.getAbsolutePath());
    }
}

Dieser Ansatz mindert mehrere Risiken: Der Dateiname wird zufällig generiert, was es für einen Angreifer schwierig macht, ihn vorherzusagen. Die Datei wird automatisch gelöscht, wenn die Java Virtual Machine (JVM) beendet wird, wodurch die Wahrscheinlichkeit sinkt, dass veraltete Dateien auftreten.

2. Stelle sicher, dass die Dateiberechtigungen korrekt sind

Beim Erstellen temporärer Dateien ist das Festlegen geeigneter Dateiberechtigungen von entscheidender Bedeutung, um unbefugten Zugriff zu verhindern. In Java lässt sich das mit den folgenden Methoden einstellen: setReadable(), setWritable() und setExecutable() dienen zur Steuerung von Dateiberechtigungen.

import java.io.File;
import java.io.IOException;

public class SecureTempFileWithPermissionsExample {
    public static void main(String[] args) throws IOException {
        File tempFile = File.createTempFile("secure_tempfile_", ".tmp");
        tempFile.setReadable(true, true);
        tempFile.setWritable(true, true);
        tempFile.setExecutable(false);
        tempFile.deleteOnExit();
        
        System.out.println("Temporary file created with secure permissions at: " + tempFile.getAbsolutePath());
    }
}

In diesem Codebeispiel ist die Datei nur vom Eigentümer lesbar und beschreibbar, wodurch das Risiko eines unbefugten Zugriffs minimiert wird.

3. Vermeide fest codierte Dateinamen

Das Verwenden fest codierter Dateinamen, wie im ersten unsicheren obigen Beispiel gezeigt, ist riskant, da dadurch der temporäre Dateiname vorhersehbar wird. Verwende immer Mechanismen, die eindeutige, unvorhersehbare Dateinamen generieren, wie File.createTempFile().

4. Behandele temporäre Dateien in einem privilegierten Kontext

Beim Umgang mit sensiblen Daten kann es von Vorteil sein, temporäre Dateien in einer kontrollierten oder privilegierten Umgebung zu verwalten. Dies ermöglicht das Erstellen der Dateien in einem Verzeichnis mit eingeschränktem Zugriff oder auch den Einsatz des Java AccessController, mit dem sich strengere Sicherheitsrichtlinien für Dateivorgänge durchsetzen lassen.

Erweiterte Überlegungen

5. Verwende das Paket java.nio.file

Das in Java 7 eingeführte Paket java.nio.file bietet robustere und flexiblere Mechanismen für die Dateiverwaltung, einschließlich der Erstellung temporärer Dateien. Die Files-Klasse bietet die createTempFile()-Methode, die auch Dateiattribute wie Berechtigungen angeben kann. Das Codebeispiel zeigt, wie sich Dateiberechtigungen mithilfe des NIO-Pakets festlegen und so eine differenzierte Kontrolle über Dateisicherheitsattribute durchsetzen lassen:

import java.io.File;
import java.io.IOException;

public class SecureTempFileWithPermissionsExample {
    public static void main(String[] args) throws IOException {
        File tempFile = File.createTempFile("secure_tempfile_", ".tmp");
        tempFile.setReadable(true, true);
        tempFile.setWritable(true, true);
        tempFile.setExecutable(false);
        tempFile.deleteOnExit();
        
        System.out.println("Temporary file created with secure permissions at: " + tempFile.getAbsolutePath());
    }
}

6. Erwäge die Verwendung von In-Memory-Lösungen

Für einige Anwendungen ist es möglich, auf das Erstellen temporärer Dateien ganz zu verzichten, indem sie In-Memory-Speicherlösungen wie ByteArrayOutputStream für temporäre Daten verwenden. In-Memory-Lösungen können temporäre Dateien in Java-Anwendungen ersetzen, was zu einer höheren Effizienz und schnelleren Verarbeitung führt. Sie sind besonders vorteilhaft für Anwendungen, die nur während der Laufzeit Daten benötigen. Allerdings gibt es auch Nachteile, wie den erhöhten Speicherbedarf, die Flüchtigkeit der Daten, Herausforderungen bei der Skalierung sowie Sicherheitsrisiken, die sorgfältig berücksichtigt werden müssen.

Der In-Memory-Ansatz eliminiert aber die mit dateisystembasierter temporärer Speicherung verbundenen Risiken, eignet sich jedoch nur eingeschränkt für große Datensätze oder Anwendungen mit erheblichen Speicherbeschränkungen.

Um eine sichere Handhabung temporärer Dateien in Java zu gewährleisten, sollten Entwickler die folgenden Best Practices beherzigen:

Bevorzuge sichere Standardeinstellungen: Verwende immer Methoden wie File.createTempFile() oder Files.createTempFile(), die sichere Standardeinstellungen für die Dateierstellung bereitstellen.

Dateiberechtigungen explizit festlegen: Stelle sicher, dass temporäre Dateien über die minimal erforderlichen Berechtigungen verfügen und vermeide, anderen Benutzern unnötig Zugriff zu gewähren.

Vermeide vorhersehbare Dateinamen: Verwende niemals fest codierte oder vorhersehbare Namen für temporäre Dateien. Generiere immer eindeutige Dateinamen mithilfe sicherer APIs.

Verwende deleteOnExit(): Wann immer möglich, verwende deleteOnExit() um sicherzustellen, dass temporäre Dateien automatisch bereinigt werden, wenn die JVM beendet wird.

Begrenze den Umfang temporärer Dateien: Speichere temporäre Dateien in Verzeichnissen mit eingeschränktem Zugriff und erwäge die Erstellung eines dedizierten Verzeichnisses für temporäre Dateien, die strengere Sicherheitskontrollen erfordern.

Behandele Ausnahmen ordnungsgemäß: Behandele beim Arbeiten mit temporären Dateien stets sämtliche Ausnahmen, um sicherzustellen, dass die Anwendung auch dann sicher und stabil weiterarbeitet, wenn Dateivorgänge fehlschlagen.

Durch Befolgen der beschriebenen Richtlinien und Best Practices können Java-Entwickler die mit CWE-377 verbundenen Risiken mindern und sicherstellen, dass ihre Anwendungen temporäre Dateien sicher verarbeiten. Das Verwenden sicherer APIs, ordnungsgemäßer Dateiberechtigungen und sorgfältiger Dateiverwaltungspraktiken sind für das Aufrechterhalten der Vertraulichkeit, Integrität und Verfügbarkeit von Daten innerhalb einer Java-Anwendung von entscheidender Bedeutung.

Die sichere Verwaltung temporärer Dateien ist nicht nur eine Best Practice, sondern ein entscheidender Aspekt bei der Entwicklung robuster, sicherer Java-Anwendungen. Das Einhalten dieser Grundsätze schützt Anwendungen vor häufigen Bedrohungen und trägt zu einem sichereren Software-Ökosystem bei.