Secure Coding: Unbefugten Zugriff durch Path Traversal (CWE-22) verhindern

CWE-22 beschreibt die unsachgemäße Veränderung eines Pfadnamens auf ein eingeschränktes Verzeichnis. Wie lässt sich die Schwachstelle in den Griff bekommen?

In Pocket speichern vorlesen Druckansicht 68 Kommentare lesen
Secure Coding: Unbefugten Zugriff durch Path Traversal (CWE-22) verhindern

(Bild: erstellt mit ChatGPT / DALL-E)

Lesezeit: 8 Min.
Von
  • Sven Ruppert
Inhaltsverzeichnis

Die Common Weakness Enumeration CWE-22, allgemein als „Path Traversal“ bezeichnet, ist eine Schwachstelle, bei der eine Anwendung die Pfade, auf die Benutzer über eine vom Benutzer bereitgestellte Eingabe zugreifen können, nicht angemessen einschränkt. Dies kann es Angreifern ermöglichen, auf Verzeichnisse und Dateien außerhalb des vorgesehenen Verzeichnisses zuzugreifen, was zu unbefugtem Zugriff und einer möglichen Systemkompromittierung führen kann. Diese Schwachstelle ist in Java-Anwendungen aufgrund des allgegenwärtigen Einsatzes von Dateiverarbeitungs- und Webressourcen besonders bedeutsam. Dieser Beitrag befasst sich mit der Natur von CWE-22, seinen Auswirkungen, Ausnutzungsmethoden und vor allem mit den Strategien zur Minderung solcher Schwachstellen in Java-Anwendungen.

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.

CWE-22 ist als "Unsachgemäße Beschränkung eines Pfadnamens auf ein eingeschränktes Verzeichnis (Path Traversal)" kategorisiert. Die Schwachstelle tritt auf, wenn eine Anwendung mithilfe von Benutzereingaben einen Pfad ohne ordnungsgemäße Validierung oder Bereinigung erstellt, sodass jemand Pfade angeben kann, die außerhalb des vorgesehenen Verzeichnisses verlaufen. Sequenzen wie ../ lassen sich verwenden, um in der Verzeichnisstruktur eine Ebene nach oben zu gelangen.

Ein typischer Java-Codeausschnitt, der eine Datei basierend auf Benutzereingaben liest, sieht beispielsweise wie folgt aus:

String fileName = request.getParameter("file");
File file = new File("/var/www/uploads/" + fileName);
FileInputStream fis = new FileInputStream(file);

Ist der Parameter fileName nicht ordnungsgemäß validiert, kann ein Angreifer ihn manipulieren, um auf Dateien außerhalb des Verzeichnisses /var/www/uploads/, wie z. B. /etc/passwd, zuzugreifen, indem er eine Pfaddurchquerungssequenz (`. ./../etc/passwd`) verwendet.

Die Auswirkungen von CWE-22 können schwerwiegend sein und vom unbefugten Zugriff auf sensible Dateien bis hin zur vollständigen Systemkompromittierung reichen. Zu den möglichen Auswirkungen gehören:

  • Offenlegung sensibler Informationen: Angreifer können auf sensible Dateien wie Konfigurationsdateien, Passwörter und persönliche Daten zugreifen.
  • Kompromittierung bei der Datenintegrität: Angreifer können Dateien ändern, was möglicherweise zur Datenbeschädigung oder Ă„nderung kritischer Anwendungsdateien fĂĽhrt.
  • Denial of Service (DoS): Angreifer können den normalen Betrieb stören, indem sie auf Systemdateien zugreifen und diese ändern.
  • AusfĂĽhrung eines willkĂĽrlichen Codes: Im Extremfall können Angreifer beliebigen Code ausfĂĽhren, wenn sie Zugriff auf ausfĂĽhrbare Dateien oder Skripte erhalten.

Ausbeutungstechniken

Um eine Path-Traversal-Schwachstelle auszunutzen, verwendet ein Angreifer normalerweise Sonderzeichen und Muster in der Eingabe, um durch das Dateisystem zu navigieren. Einige der Standardtechniken dabei sind:

  • Punkt-Punkt-Schrägstrich (../): Die häufigste Methode, bei der der Angreifer ../ verwendet, um die Verzeichnisstruktur nach oben zu verschieben.
  • Kodierte Zeichen: Angreifer können URL-Kodierung (%2e%2e%2f) oder andere Kodierungsschemata verwenden, um einfache Eingabefilter zu umgehen.
  • Null-Byte-Injection: Manchmal werden Nullbytes (%00) verwendet, um Zeichenfolgen vorzeitig zu beenden, wodurch alle angehängten Erweiterungen oder Pfadkomponenten effektiv ignoriert werden.

Schadensbegrenzungsstrategien in Java

Die potenziellen Gefahren durch CWE-22 in Java abzuschwächen, erfordert eine Kombination aus sicheren Programmierpraktiken, Eingabevalidierung und ordnungsgemäßer Verwendung von APIs. Empfehlenswerte Strategien dazu sind:

Kanonisierung und Normalisierung

Stellen Sie sicher, dass die Dateipfade vor der Verwendung normalisiert werden. Java bietet Methoden zur Normalisierung von Pfaden, die dabei helfen können, Traversal-Angriffe abzuschwächen.

  import java.nio.file.Paths;
   import java.nio.file.Path;

   public File getFile(String fileName) throws IOException {
       Path basePath = Paths.get("/var/www/uploads/");
       Path filePath = basePath.resolve(fileName).normalize();

       if (!filePath.startsWith(basePath)) {
           throw new SecurityException("Attempted path traversal attack detected");
       }

       return filePath.toFile();
   }

Eingabevalidierung und -bereinigung

Führen Sie eine strenge Validierung der Benutzereingaben durch. Lehnen Sie alle Eingaben ab, die potenziell schädliche Muster wie ../, URL-codierte Sequenzen oder andere Traversal-Muster enthalten.

 public String sanitizeFileName(String fileName) {
       if (fileName == null 
             || fileName.contains("..") 
             || fileName.contains("/") 
             || fileName.contains("\\")) {
           throw new IllegalArgumentException("Invalid file name");
       }
       return fileName;
   }

Whitelist-Ansatz

Verwenden Sie eine Whitelist, um Dateinamen anhand einer Reihe zulässiger Werte oder Muster zu validieren. Dies kann effektiver sein, als bekannte destruktive Muster auf die Blacklist zu setzen.

  public boolean isValidFileName(String fileName) {
       return fileName.matches("[a-zA-Z0-9._-]+");
   }

Sicherheitsmanager und Berechtigungen

Verwenden Sie den Sicherheitsmanager von Java, um den Zugriff auf das Dateisystem einzuschränken. Das fügt eine zusätzliche Schutzebene ein, mit dem Durchsetzen von Zugriffskontrollrichtlinien zur Laufzeit. Hierbei ist allerdings die jeweilige Java-Version zu beachten, da der SecurityManager in einer der künftigen JDK-Versionen entfallen soll.

   System.setSecurityManager(new SecurityManager());

Dateizugriffskontrollen

Beschränken Sie die Dateiberechtigungen auf dem Server, um den Zugriff nur auf die erforderlichen Dateien und Verzeichnisse einzugrenzen. Das verringert die Auswirkungen potenzieller Exploits. Hierbei muss der Prozess des Webservice unter einem definierten User laufen, dessen Rechte bis auf das absolut notwendige eingeschränkt sind.

Protokollierung und Ăśberwachung

Implementieren Sie eine umfassende Protokollierung und Überwachung, um verdächtige Aktivitäten zu erkennen und darauf zu reagieren. Protokolle sollten genügend Details erfassen, um potenzielle Ausnutzungsversuche nachzuverfolgen.

 import java.util.logging.Logger;

   public class FileAccessLogger {
       private static final Logger LOGGER = 
                    Logger.getLogger(
                        FileAccessLogger.class.getName());

       public void logAccessAttempt(String fileName) {
           LOGGER.warning("Attempted access to file: " + fileName);
       }
   }

Betrachten wir eine hypothetische Fallstudie, um die Anwendung der genannten Abhilfestrategien zu veranschaulichen. Angenommen, wir haben eine einfache Java-Webanwendung, die es Benutzern ermöglicht, Dateien von einem Server herunterzuladen.

@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                                  throws ServletException, IOException {
        String fileName = request.getParameter("file");
        File file = new File("/var/www/uploads/" + fileName);
        
        if (file.exists()) {
            FileInputStream fis = new FileInputStream(file);
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", 
                                                "attachment; filename=\"" + file.getName() + "\"");
            
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                response.getOutputStream().write(buffer, 0, bytesRead);
            }
            fis.close();
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
}

Dieses Servlet liest den Parameter file aus der Anfrage und erstellt ein File-Objekt. Ohne ordnungsgemäße Validierung kann ein Angreifer dies ausnutzen, um beliebige Dateien vom Server herunterzuladen.

@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                                  throws ServletException, IOException {
        String fileName = sanitizeFileName(request.getParameter("file"));
        
        Path basePath = Paths.get("/var/www/uploads/");
        Path filePath = basePath.resolve(fileName).normalize();
        
        if (!filePath.startsWith(basePath)) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid file path");
            return;
        }
        
        File file = filePath.toFile();
        if (file.exists()) {
            FileInputStream fis = new FileInputStream(file);
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", 
                                                "attachment; filename=\"" + file.getName() + "\"");
            
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                response.getOutputStream().write(buffer, 0, bytesRead);
            }
            fis.close();
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

    private String sanitizeFileName(String fileName) {
        if (fileName == null 
                || fileName.contains("..") 
                || fileName.contains("/") 
                || fileName.contains("\\")) {
            throw new IllegalArgumentException("Invalid file name");
        }
        return fileName;
    }
}

In der sicheren Version stellt die Methode sanitizeFileName sicher, dass der Dateiname frei von Traversierungssequenzen ist, und der Pfad wird normalisiert und ĂĽberprĂĽft, um ein Directory Traversal zu verhindern.

CWE-22 (Path Traversal) ist eine kritische Schwachstelle, die schwerwiegende Folgen haben kann, wenn sie nicht angemessen entschärft wird. In Java-Anwendungen ist es wichtig, eine Kombination aus sicheren Programmierpraktiken, Eingabevalidierung, Kanonisierung und Zugriffskontrollen einzusetzen, um sich vor dieser Bedrohung zu schützen. Durch das Verständnis der Natur von CWE-22 und die Implementierung robuster Sicherheitsmaßnahmen können Entwickler das Risiko eines unbefugten Dateizugriffs erheblich reduzieren und ihre Anwendungen vor potenzieller Ausnutzung schützen.