Java-URLs sicher kodieren und dekodieren
Jura Gorohovsky
14. August 2023
0 Min. LesezeitURL-Kodierung sorgt dafür, dass Ihre URL nur gültige Zeichen enthält, damit der empfangende Server sie korrekt interpretieren kann. Gemäß dem RFC-3986-Standard enthalten URIs (die eine Obermenge von URLs darstellen) nur eine begrenzte Auswahl an Zeichen: Ziffern, Buchstaben und einige grafische Symbole aus dem ASCII-Zeichensatz.
Enthält eine URL Zeichen außerhalb dieser begrenzten Auswahl, müssen diese prozentkodiert werden. Bei der Prozentkodierung wird ein Zeichen in eine zweistellige Hexadezimaldarstellung aus acht Bits umgewandelt, der das Escape-Zeichen % vorangestellt wird. Dasselbe gilt für Trennzeichen (z. B. &, /, ? oder #), die zwar zum ASCII-Zeichensatz gehören, aber außerhalb ihrer vorgesehenen strukturellen Position in der URL verwendet werden.
Bei der URL-Dekodierung wird eine prozentkodierte URL wieder in ihre ursprüngliche Form zurückverwandelt und dabei werden nicht standardisierte Zeichen wiederhergestellt.
Wichtig ist: Kodierung ist keine Verschlüsselung. Bei der Verschlüsselung werden Informationen mithilfe eines geheimen Schlüssels verändert, sodass nur der vorgesehene Empfänger auf die ursprünglichen Informationen zugreifen kann. Die URL-Kodierung soll dagegen URL-Bestandteile nicht vor außenstehenden Personen verbergen. Sie sorgt vielmehr dafür, dass der empfangende Server die URL einfach und eindeutig interpretieren kann, und verhindert, dass die URL durch den Nutzer des Clients manipuliert wird, der sie erstellt und sendet.
Wird eine URL nicht kodiert, kann das verschiedene Probleme verursachen. Ihre Anwendung kann beispielsweise möglicherweise keine URL für den Versand an den Server erstellen. Außerdem kann der Server, der die URL empfängt, sie unter Umständen nicht korrekt analysieren und mit einer Fehlermeldung antworten. Eine nicht kodierte URL kann auch manipuliert werden und Ihre Anwendung potenziellen Sicherheitsrisiken aussetzen.
Jede Programmiersprache bietet eine oder mehrere APIs zum Kodieren und Dekodieren von URLs. In diesem Artikel geht es um Java, die Bedeutung der URL-Kodierung und -Dekodierung und die richtige Vorgehensweise.
Was bedeutet URL-Kodierung und -Dekodierung in Java?
In Java ist die URL-Kodierung und -Dekodierung insbesondere in folgenden Anwendungsfällen wichtig:
Verarbeitung freier Daten, die Besucher in ein HTML-Formular eingeben, etwa in ein Suchformular.
Erstellen von Aufrufen an eine externe API aus dem Code, indem einer Basis-URL Abfrageparameter hinzugefügt werden.
Erstellen von Aufrufen an ein API-Gateway, das Anfragen zur weiteren Weiterleitung an interne Services verwendet.
Eine URL hat folgende Struktur:

Normalerweise müssen Sie nicht die gesamte URL kodieren. Natürlich kann der Pfad beispielsweise Leerzeichen enthalten, wenn Nutzer Dateien hochladen – für Hostnamen gibt es sogar Punycode. In den meisten Fällen kontrollieren Sie jedoch Host- und Pfadabschnitte. Daher müssen Sie nur die Teile einer URL einzeln kodieren, die variable Daten enthalten, also etwa Parameterwerte in einer Abfragezeichenfolge.
Ein konkreter Fall, in dem Sie die gesamte URL kodieren müssen, liegt vor, wenn diese URL als Parameter in der Abfragezeichenfolge einer anderen URL übergeben wird.
Sichere URL-Kodierung und -Dekodierung in Java implementieren
Um die URL-Kodierung und -Dekodierung in Java besser zu verstehen, sehen wir uns zwei Klassen an, die in Java-Anwendungen häufig zum Kodieren und Dekodieren von Abfragezeichenfolgen-Parametern verwendet werden.
URLs in Java kodieren
Um die Werte von Abfragezeichenfolgen-Parametern in einer Java-Anwendung prozentzukodieren, verwenden Sie normalerweise die Klasse java.net.URLEncoder und ihre Methode encode().
Die Methode encode() führt genau Folgendes aus:
Sie stellt sicher, dass alle alphanumerischen Zeichen – etwa
abisz,AbisZ,0bis9,sowie die Sonderzeichen.,-,*und_– unverändert bleiben.Sie wandelt das Leerzeichen in ein Pluszeichen
+um.Alle anderen Zeichen werden prozentkodiert.
Diese Methode wurde entwickelt, um Daten aus HTML-Formularen für die Übermittlung vorzubereiten. Dazu wandelt sie sie in das MIME-Format application/x-www-form-urlencoded um, das sich für die Kodierung von URL-Abfrageparameterwerten eignet.
Die Methode encode() gibt es in drei überladenen Varianten:
1. Mit encode(String s, String enc) können Sie das Kodierungsschema explizit als Zeichenfolge festlegen (UTF-8 wird empfohlen). Sie können diese Variante verwenden, beachten Sie jedoch, dass sie eine geprüfte Ausnahme vom Typ UnsupportedEncodingException auslöst. Ihr Code muss diese daher mit einer @throws-Deklaration oder einem try/catch-Block behandeln. Beachten Sie außerdem, dass Zeichenfolgenliterale Tippfehler verursachen können:
2. encode(String s, Charset charset) ist seit Java 10 verfügbar und bislang die beste Variante. Sie verwenden eine Konstantendefinition für UTF-8 (StandardCharsets.UTF_8). Dadurch vermeiden Sie Tippfehler bei der Angabe der Kodierung und lösen keine geprüften Ausnahmen aus. Sie müssen diese also nicht behandeln, damit Ihr Code kompiliert:
3. encode(String s) ist die älteste Variante und in OpenJDK 17 als veraltet gekennzeichnet. Sie sollten sie nicht verwenden, da sie die Standardkodierung der Plattform nutzt, auf der die Java Virtual Machine (JVM) ausgeführt wird. Dabei ist UTF-8 nicht garantiert.
Die Methode URLEncoder.encode() hat eine Eigenheit: Sie kodiert ein Leerzeichen als Pluszeichen statt als %20 – vermutlich, weil sie einer Beschreibung von Abfragezeichenfolgen in einem älteren Standard folgt. Deshalb ändern Entwickler manchmal die Ausgabe von encode() und ersetzen das Pluszeichen durch %20, um ein Leerzeichen darzustellen:
Angenommen, Sie möchten über die GitHub REST API nach Repositories suchen. GitHub bietet zahlreiche Suchfilter, mit denen sich Ergebnisse nach Programmiersprache, Repository-Größe und Sichtbarkeit eingrenzen lassen. Eine Suche nach "user:defunkt forks:>100" liefert beispielsweise alle Repositories des Nutzers defunkt mit mindestens 100 Forks. Sie können all diese Filter in API-Aufrufen verwenden, müssen sie jedoch in den Abfrageparameter q einfügen:
In diesem Code enthält searchQuery eine Reihe von Suchfiltern, mit denen Sie alle öffentlichen Java-Repositories finden, die seit 2018 aktualisiert wurden und zwischen 100 und 1.000 Sterne haben. Der Wert im Beispiel ist fest kodiert, könnte aber auch aus einer Datei oder Datenbank stammen oder direkt von einem Nutzer über eine Web- oder Mobilanwendung eingegeben werden.
Beim Erstellen von url setzt dieser Code drei Zeichenfolgen zusammen:
Die Basis-URL der API, das Trennzeichen
?für die Abfragezeichenfolge, der Parameterqund sein Zuweisungstrennzeichen=: "https://api.github.com/search/repositories?q=".searchQuery, der Wert des Parametersq, wird mitURLEncode()prozentkodiert.Die übrigen Abfrageparameter müssen nicht kodiert werden, da sie fest kodiert sind und keine unzulässigen Zeichen enthalten.
Bei der Ausführung dieses Codes ergibt sich die URL https://api.github.com/search/repositories?q=language%3AJava+stars%3A100..1000+pushed%3A%3E2018-01-01+is%3Apublic&per_page=10&sort=stars&order=desc. Der Wert von q wird zu la nguage%3AJava+stars%3A100..1000+pushed%3A%3E2018-01-01+is%3Apublic kodiert. Dabei wird : durch %3A, werden Leerzeichen durch + und wird > durch %3E ersetzt.
URLs in Java dekodieren
Die explizite Dekodierung von URL-Abfrageparametern ist seltener erforderlich, da viele Frameworks, darunter Spring Boot, die Dekodierung automatisch übernehmen.
Wenn Sie kein Framework verwenden, sollte sich das weitere Vorgehen danach richten, was Sie als Nächstes tun möchten.
Wahrscheinlich erhalten Sie die URL, um zu entscheiden, welche Aktionen ausgeführt werden sollen, etwa Daten abzufragen oder die Anfrage an einen anderen Service weiterzuleiten. In diesem Fall analysiert Ihre Verarbeitungslogik vermutlich jeden Abfrageparameter einzeln. Beginnen Sie am besten mit der Analyse der URL, extrahieren Sie die Abfragezeichenfolge und dekodieren Sie die einzelnen Parameterwerte.
Zum Dekodieren prozentkodierter Zeichen können Sie java.net.URLDecoder.decode() verwenden:
Hier enthält encodedUrl eine Google-Such-URL mit vom Browser prozentkodierten Abfrageparametern. Dieser Code erstellt ein neues Objekt uri vom Typ URI, um die gesamte Abfragezeichenfolge zu extrahieren. Das Objekt stellt die Methode getRawQuery() bereit, die nur die Abfragezeichenfolge zurückgibt, wobei alle Parameterwerte weiterhin kodiert sind:
Anschließend teilt der Code die unverarbeitete Abfragezeichenfolge am Trennzeichen & auf. Das Ergebnis ist ein Array mit einzelnen Parameter-Wert-Paaren. Jedes Paar wird so umgewandelt, dass der Parameter unverändert bleibt und der Wert dekodiert wird. Schließlich werden alle umgewandelten Paare in einer Liste gesammelt:
Sobald alle Parameter voneinander getrennt und ihren jeweiligen Werten zugeordnet sind, können Sie die erforderliche Logik anwenden, um sie zu validieren und die nächsten Schritte Ihrer Anwendung festzulegen.
Best Practices für den Umgang mit URLs in Java
Bei der Arbeit mit URLs in Java sollten Sie einige Best Practices beachten, damit sie korrekt verarbeitet werden und keine potenziellen Probleme auftreten.
URL-Kodierung nicht überspringen
Wenn Sie URLs nicht kodieren, müssen Sie mit Überraschungen rechnen – von Laufzeitausnahmen bis hin zu missverständlichen Antworten der Server, die Sie erreichen möchten.
Sehen wir uns dazu noch einmal unser Beispiel mit dem GitHub-API-Aufruf an und betrachten wir, was passiert, wenn Sie die Suchparameter nicht kodieren:
Beachten Sie: Im folgenden Codebeispiel kapselt sendGetRequest(url) das Erstellen einer HTTP-Anfrage mithilfe der Request-Builder-API von Java 11:
Wenn Sie diesen Code ausführen, ohne searchQuery zu kodieren, schlägt er zur Laufzeit fehl. Der URI-Konstruktor kann aus einer Zeichenfolge mit einem nicht kodierten Leerzeichen kein URI-Objekt erstellen:
Aber was, wenn Sie unbedingt trotzdem eine Anfrage senden möchten? Sie könnten die Scanner-API ausprobieren, die ein URL-Objekt (statt eines URI-Objekts) entgegennimmt und damit einen Eingabestream ausliest:
Das funktioniert tatsächlich. Die API-Anfrage erreicht ihr Ziel, doch sie gibt den Fehler 400 Bad Request zurück. Dieser weist auf einen vermuteten clientseitigen Fehler hin, etwa eine fehlerhafte Anfragesyntax:
Rotem Bar zeigt anschaulich, wie nicht kodierte URLs bei der REST-basierten Kommunikation zwischen Services manipuliert werden können.
Eines der von Rotem beschriebenen Szenarien, in denen eine URL-Manipulation möglich ist, betrifft einen Service, der Folgendes tut:
Er übernimmt Parameter aus einer vom Client stammenden URL.
Er erstellt eine neue URL, um einen anderen Service aufzurufen.
Hier ist ein Codebeispiel, das dieses Szenario nachbildet:
Wie Sie sehen, wird es Ihnen früher oder später zum Verhängnis, wenn Sie bei einem nicht trivialen Wert wie dem des Parameters q die URL-Kodierung überspringen. Selbst wenn Sie Glück haben und eine erfolgreiche Antwort vom Server erhalten, können Sie nicht sicher sein, ob sie das Erwartete enthält oder ob Sie nur versehentlich eine Sicherheitslücke im Server ausgenutzt haben.
Apropos Sicherheitslücken: Wenn URL-Parameter nicht kodiert werden, können leicht welche entstehen. Mehr dazu erfahren Sie im Artikel "Developers, Please encode your URLs".
Der Service übernimmt zwei Parameter, key und user, und validiert den Nutzer zuverlässig. key wird jedoch nicht validiert, sondern beim Erstellen einer neuen URL unverändert übernommen. Keiner der Abfrageparameter in dieser neuen URL wird kodiert.
Bei einer legitimen Eingabe erstellt der Service wie erwartet eine neue URL:
Doch was passiert, wenn ein Angreifer eine URL mit einem manipulierten Parameter key übermittelt?
Folgendes geschieht:
Der vom Client übergebene Wert von
keylautet55s72502010a&user=admin#. Der Service hängt den Schlüssel ohne Kodierung an die URL an.Der Service validiert den Parameter
userwie gewohnt.legitusergilt weiterhin als legitim – denn das ist er auch.Da der ursprüngliche
key-Parameter ein&-Zeichen enthält, das in der URL-Abfragezeichenfolge als Trennzeichen zwischen Parametern dient, enthält die resultierende URL zwei Parameter:key=55s72502010aunduser=admin. Dabei handelt es sich um zwei Teilzeichenfolgen des vom Client übermittelten Schlüssels. Wie Sie sehen, hat der Dienst zwar den Benutzerlegituservalidiert, doch die resultierende URL gibt einen anderen Benutzer vor, der möglicherweise über erhöhte Berechtigungen verfügt. Dieser Benutzer hat die Validierung umgangen.Da der ursprüngliche
key-Parameter mit dem Zeichen#endet, das in URLs als Fragment-Trennzeichen dient, wird der Teil&user=legituserder ursprünglich vom Client übermittelten URL in den Fragmentbereich verschoben und effektiv ignoriert.
Das Ergebnis ist eine URL, die einen nicht zugehörigen und nicht verifizierten Benutzer repräsentiert – ein Angriff zur Rechteausweitung.
Wie können Sie sich also gegen diesen Angriff schützen? Eine Möglichkeit wäre, neben dem key-Wert auch den user zu validieren. Diese Validierung soll jedoch möglicherweise von einem anderen Dienst in der Anfragekette übernommen werden. In diesem Fall ist es einfacher, die Parameterwerte beim Erstellen einer neuen URL zu kodieren:
Sehen Sie, was passiert, wenn jemand mit dieser Änderung versucht, den bösartigen key-Wert zu übermitteln:
Der kodierte key-Wert (key=55s72502010a%26user%3Dadmin%23) verhindert den versuchten Angriff zur Rechteausweitung, da & als %26 und # als %23 percent-kodiert werden. Die resultierende URL wird mit dem korrekten Benutzernamen an den nächsten Dienst weitergegeben. Möglicherweise gibt der nächste Dienst einen Fehler zurück, nachdem er den manipulierten key-Parameter nicht interpretieren konnte. Eine Fehlermeldung ist jedoch immer besser als ein Angriff.
Verwenden Sie Standardbibliotheken zum Kodieren und Dekodieren von URLs
In Java verwenden Sie zum Percent-Kodieren von Abfrageparametern wahrscheinlich meistens URLEncoder.encode() und URLDecoder.decode(), denn diese zuverlässigen Tools sind standardmäßig in jedem Java-Projekt verfügbar.
Alternativ können Sie die Bibliothek Open Web Application Security Project (OWASP) Java Encoder verwenden. Ihr Hauptzweck ist zwar die Eingabevalidierung für verschiedene Kontexte, sie enthält aber auch die Methode Encode.forUriComponent(), mit der sich URL-Parameterwerte und REST-Pfade kodieren lassen. Diese Bibliothek ist eine gute Wahl, wenn Ihre Java-Anwendung vom Client übermittelte URLs und ihre Bestandteile sicher in verschiedenen UI-Steuerelementen anzeigen muss.
Je nach verwendetem Framework müssen Sie die Dekodierung möglicherweise gar nicht explizit vornehmen oder anders umsetzen:
In Spring oder Spring Boot ermöglicht die Annotation
@RequestParaman einem Controller-Parameter die automatische Dekodierung des Parameterwerts.In einer GWT-Anwendung verwenden Sie wahrscheinlich Methoden aus der GWT-eigenen Klasse `com.google.gwt.http.client.URL`.
Android bietet eine separate API zum Erstellen von URLs, die auch die Kodierung von Abfrageparametern umfasst.
Wenn Sie Drittanbieterbibliotheken zum Kodieren und Dekodieren von URLs verwenden, sollten Sie diese auf bekannte Sicherheitslücken prüfen. Werden Schwachstellen gefunden, aktualisieren Sie die Bibliotheken, sobald Sicherheitsupdates verfügbar sind.
Validieren und bereinigen Sie URLs, bevor Sie in Ihrer Anwendung mit ihnen interagieren
URL-Kodierung ist nur ein Teil der Lösung. Wenn Ihre Webanwendung Daten von Benutzern über URL-Parameter entgegennimmt und diese anschließend an die Webanwendung zurückgibt, sollten Sie sicherstellen, dass die Benutzerdaten unbedenklich sind, bevor Sie sie wieder in den Browser-Kontext einfügen.
Das bedeutet, dass Sie Benutzerdaten validieren sollten – auch solche, die serverseitig über URLs eingehen. Prüfen Sie dabei sowohl Syntax als auch Semantik der Benutzerdaten und verwenden Sie Positivlisten, da Negativlisten anfälliger für Fehler und Lücken sind.
Wenn Ihre Anwendung Benutzern außerdem das Übermitteln von HTML-Code ermöglicht, sollten Sie eine HTML-Bereinigung implementieren. Eine hierfür häufig verwendete Java-Bibliothek ist der OWASP Java HTML Sanitizer.
Unsichere URLs mit der Snyk Security Extension für IntelliJ IDEA finden
URL-Kodierung und -Dekodierung sollten Teil umfassenderer Sicherheitspraktiken sein, etwa der Kodierung und Maskierung von Daten sowie der Eingabevalidierung. Sicheren Code zu schreiben ist entscheidend. Je früher Sie Sicherheitslücken im Entwicklungszyklus erkennen, desto geringer sind sowohl die Kosten für ihre Behebung als auch die Auswirkungen von Sicherheitsvorfällen.
Als Java-Entwickler, der mit IntelliJ IDEA arbeitet, profitieren Sie möglicherweise von der Installation der Erweiterung Snyk Security.
Snyk Security findet Probleme, hebt sie im Code-Editor hervor und hilft Ihnen, bekannte Sicherheitslücken in folgenden Bereichen zu beheben:
Ihrem eigenen Code
Direkten und transitiven Open-Source-Abhängigkeiten, die Sie in Ihr Projekt einbinden
Ihren Docker-Images
Ihren Infrastructure-as-Code-Vorlagen
Die Snyk Security Extension hilft Ihnen, Probleme wie nicht bereinigte Eingaben aus URL-Parametern zu erkennen, die zu Cross-Site-Scripting-Angriffen (XSS), Command Injection, Server-Side Request Forgery (SSRF) oder Open-Redirect-Schwachstellen führen können. Für jede erkannte Sicherheitslücke zeigt sie, wie verschiedene Java-Open-Source-Projekte ähnliche Probleme in der Vergangenheit behoben haben:

Hier finden Sie die vollständige Liste der Sicherheitsprüfungen, die Snyk Security für Ihren Java-Code durchführt.
Fazit
URL-Parameter nicht zu kodieren, mag wie ein kleines Versäumnis wirken. Wie dieser Artikel jedoch zeigt, kann es die Zuverlässigkeit und Sicherheit Ihrer Java-Anwendungen erheblich beeinträchtigen. Durch das Percent-Kodieren von URL-Parametern erhalten legitime Benutzer die erwarteten Ergebnisse, während böswillige Akteure daran gehindert werden, Zugriffskontrollen zu umgehen und Angriffe auszuführen.
URL-Kodierung und -Dekodierung sind zwar nur Teil eines umfassenderen Sets bewährter Sicherheitspraktiken, doch stabile APIs und intelligente Entwicklertools wie die Snyk Security Extension für IntelliJ IDEA helfen Ihnen, Fehler zu vermeiden, kontinuierlich sicheren Code bereitzustellen und zeitaufwendige Nacharbeiten nach Sicherheitsvorfällen in der Produktionsumgebung zu vermeiden.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.



