" /> " />
Sprache : en | de | fr | es
Zurück zu den Blogs
nächster Beitrag ▶
%20 in der URL: Was es bedeutet und warum es in Webadressen vorkommt

Doppelte Kodierung in URLs

Doppelte Kodierung in URLs tritt auf, wenn bereits kodierte Zeichen noch einmal kodiert werden. Anstatt %20 für ein Leerzeichen erhält man möglicherweise %2520, weil das Prozentzeichen selbst in %25 kodiert wurde. Dieses Problem sieht in Logs klein aus, bricht aber Weiterleitungen, API-Parameter, Dateipfade, Signaturen und Sicherheitsfilter.

Das Thema ist wichtig, weil die URL-Kodierung normalerweise auf mehreren Ebenen gleichzeitig behandelt wird: Browser, Client-Bibliothek, Proxy, Framework, Router und Anwendungscode. Wenn zwei Ebenen beide beschließen zu "helfen", ändert die endgültige URL ihre Bedeutung. In der Produktion erscheint dies oft als defekte Callback-URL, ein fehlgeschlagener OAuth-Flow, eine fehlende Datei oder eine Route, die in der Staging-Umgebung funktioniert, aber nicht hinter einem Gateway.

Warum doppelt kodierte URLs in realen Systemen auftreten

Eine URL sollte an der richtigen Stelle und nur für den relevanten Teil kodiert werden. Probleme beginnen, wenn Entwickler den vollständigen String manuell kodieren und ihn dann an ein Tool übergeben, das ihn erneut kodiert.

Häufige Ursachen sind:

  • einen Query-Parameter kodieren, bevor er an URLSearchParams übergeben wird
  • eine vollständige Weiterleitungs-URL kodieren und sie dann in eine andere URL einbetten
  • Framework-Middleware, die bereits verarbeitete Werte umschreibt
  • Frontend-Code, der kodierten Input an ein Backend sendet, das ihn erneut kodiert
  • Proxy- oder WAF-Regeln, die Anforderungskomponenten unerwartet transformieren

Ein einfaches visuelles Beispiel

Angenommen, der ursprüngliche Wert ist:

/docs/My File.pdf

Korrekte einfache Kodierung für ein Pfad-Fragment:

/docs/My%20File.pdf

Nach einem zweiten Durchgang wird daraus:

/docs/My%2520File.pdf

Der Server kann jetzt nach einer Datei suchen, die buchstäblich %20 in ihrem Namen enthält, anstatt ein Leerzeichen.

Wie das Problem der doppelten URL-Kodierung aussieht

Der schwierigste Teil ist, dass die URL immer noch "kodiert" aussieht, sodass Teams zuerst die falsche Ebene debuggen. Symptome hängen vom Kontext ab.

Typische Produktionssymptome

Symptom

Was man sieht

Wahrscheinliche Ursache

Defekte Weiterleitung

Benutzer landet auf Fehlerseite oder falscher Route

Weiterleitungsziel doppelt kodiert

Ungültige API-Abfrage

Backend erhält verstümmelten Filterwert

Client und Server kodieren beide

Signatur-Fehler

HMAC- oder signierte URL-Prüfung schlägt fehl

Kodierung nach dem Signieren geändert

Fehlende Datei oder Asset

Pfad wird falsch aufgelöst

Kodiertes Pfad-Segment erneut kodiert

Sicherheitsregel-Umgehung oder Fehlalarm

Filter verhält sich inkonsistent

Verschiedene Dekodierungsstufen in verschiedenen Ebenen

Warum verschachtelte URLs riskant sind

Eine klassische Falle tritt bei Return-URLs auf:

https://app.example.com/login?next=https://site.example.com/account?tab=settings

Wenn die innere URL ein Parameter-Wert werden muss, sollte sie einmal korrekt kodiert werden. Aber viele Apps kodieren sie zuerst manuell, dann kodiert ein Router oder HTTP-Client sie erneut. Das erzeugt fehlerhafte Callback-Flows und schwer lesbare Logs.

Fehler bei doppelter URL-Kodierung, die Entwickler machen

Der häufigste Fehler besteht darin, nicht zu verstehen, welche API rohe Daten erwartet und welche kodierte Daten. Gute Bibliotheken wollen normalerweise unkodierte Werte und behandeln die Maskierung intern.

Beispiel in JavaScript

Falsch:

const next = encodeURIComponent("https://site.example.com/account?tab=settings");

const url = "/login?next=" + encodeURIComponent(next);

Dies erzeugt einen zweifach transformierten Wert.

Besser:

const next = "https://site.example.com/account?tab=settings";

const url = "/login?next=" + encodeURIComponent(next);

Beispiel mit Query-Buildern

Falsches Muster:

  • name=John Doe manuell kodieren
  • das Ergebnis an einen Query-Builder übergeben
  • Query-Builder kodiert % erneut

Richtiges Muster:

  • rohen Wert John Doe übergeben
  • eine vertrauenswürdige Ebene den finalen Query-String erstellen lassen

So dekodiert man doppelt kodierte URLs sicher

Dekodierung ist nur einfach, wenn man weiß, wie viele Male der Wert transformiert wurde. Blindes wiederholtes Dekodieren ist gefährlich, besonders in sicherheitssensitivem Code, da es beabsichtigte Literale verändern oder Payloads helfen kann, die Validierung zu umgehen.

Praktischer Dekodierungsansatz

  1. Den rohen Anfragewert aus Logs oder einem Debugging-Proxy inspizieren.
  2. Einmal dekodieren und das Ergebnis vergleichen.
  3. Wenn Prozentsequenzen verbleiben, wo einfache Zeichen sein sollten, prüfen, ob eine zweite Dekodierung gerechtfertigt ist.
  4. Nur an einer kontrollierten Grenze normalisieren.
  5. Nach der Normalisierung validieren, nicht davor.

Beispiel:

Original: hello%2520world

Einmal dekodiert: hello%20world

Zweimal dekodiert: hello world

Das zeigt einen zweifach kodierten Wert. Aber daraus keine blinde "zweimal dekodieren"-Regel für jede Anfrage machen.

Sicherere Debugging-Checkliste

  • die genaue rohe URL erfassen
  • Pfad, Query und Fragment trennen
  • jeweils einen Dekodierungsschritt testen
  • prüfen, welche Ebene jede Transformation durchgeführt hat
  • bestätigen, ob der Wert kodiert bleiben sollte

Doppelte URL-Kodierung durch Design verhindern

Die beste Lösung ist architektonische Disziplin, kein Patchen.

Regeln, die in der Praxis funktionieren

  • an der Grenze kodieren, wo die finale URL zusammengestellt wird
  • interne Werte so lange wie möglich roh halten
  • niemals manuell kodieren, bevor Daten an einen vertrauenswürdigen URL-Builder übergeben werden
  • ohne besonderen Grund nicht dekodieren und neu kodieren
  • dokumentieren, ob Helfer rohe oder kodierte Eingaben erwarten
  • URLs erst nach der finalen kanonischen Form signieren

Gute Team-Konvention

Einen Ort wählen, der für die URL-Transformation verantwortlich ist:

  • Frontend-Router
  • Backend-URL-Helfer
  • API-Client-Bibliothek
  • Gateway-Normalisierungsschicht

Sobald die Verantwortung klar ist, nimmt die doppelte Maskierung stark ab.

Grenzfälle bei doppelter URL-Kodierung in verschachtelten Parametern

Einige Fälle sehen wie Bugs aus, sind aber tatsächlich beabsichtigt. Wenn zum Beispiel eine URL in eine andere als Datenwert eingebettet ist, muss die Kodierung Trennzeichen wie ?, = und & innerhalb des verschachtelten Werts erhalten. Der Schlüssel ist, dass die verschachtelte URL einmal für ihre Rolle als Parameterwert kodiert werden sollte, nicht wiederholt bei jedem Hop.

Beispiel: Weiterleitungsparameter

/auth?return_to=https%3A%2F%2Fapp.example.com%2Fdashboard%3Fpage%3D2

Das ist normal. Es wird zum Problem, wenn derselbe Wert später zu:

/auth?return_to=https%253A%252F%252Fapp.example.com%252Fdashboard%253Fpage%253D2

Diese zweite Version weist normalerweise auf zusätzliche Verarbeitung hin.

Umgang mit bereits transformierten Werten in APIs und Middleware

Framework-Stacks mischen oft automatische und manuelle Behandlung. Ein Reverse-Proxy kann einmal normalisieren, das Framework kann in Route-Parameter dekodieren, und benutzerdefinierte Middleware kann einen weiteren Durchgang anwenden. Das Ergebnis ist eine Inkonsistenz zwischen Logs, Handler-Eingabe und nachgelagerten Service-Aufrufen.

Wo zuerst prüfen

  • Rewrite-Regeln des Reverse-Proxys
  • CDN- oder WAF-Normalisierungseinstellungen
  • Route-Parameter-Extraktion
  • Weiterleitungshelfer
  • Anfrage-Builder von Drittanbieter-SDKs
  • benutzerdefinierte Sicherheitsfilter

Eine kurze Prüfung über diese Ebenen hinweg zeigt normalerweise, warum sich ein Wert mehr als erwartet geändert hat.

Fazit

Doppelte Kodierung ist selten ein Low-Level-Rätsel. Es ist normalerweise ein Koordinierungsfehler zwischen Ebenen, die alle mit derselben URL "helfen" wollen. Die Lösung besteht darin, Kodierung als Ein-Verantwortlichkeits-Schritt zu behandeln, Werte intern roh zu halten und sorgfältig an der Grenze zu normalisieren.

Wenn eine URL falsch aussieht, sie nicht einfach mit zusätzlicher Dekodierung patchen. Den vollständigen Pfad des Werts verfolgen: wo er begann, wer ihn kodierte, wer ihn erneut kodierte und ob die finale Komponente ein Pfad, ein Query-Wert oder eine verschachtelte URL war. Dieser Ansatz löst den Bug, ohne ein zerbrechlicheres System zu schaffen.