Deaktivieren der URL-Dekodierung im Nginx-Proxy

21

Wenn ich zu dieser URL navigiere, empfängt http://localhost:8080/foo/%5B-%5Dserver ( nc -l 8080) sie wie sie ist:

GET /foo/%5B-%5D HTTP/1.1

Wenn ich diese Anwendung jedoch über Nginx (1.1.19) als Proxy verwende:

location /foo {
        proxy_pass    http://localhost:8080/foo;
}

Dieselbe Anfrage, die über den Nginx-Port weitergeleitet wird, wird mit dekodiertem Pfad weitergeleitet:

GET /foo/[-] HTTP/1.1

Dekodierte eckige Klammern im GET-Pfad verursachen die Fehler auf dem Zielserver ( HTTP-Status 400 - Unzulässiges Zeichen im Pfad ... ), wenn sie ohne Escapezeichen eintreffen.

Gibt es eine Möglichkeit, die URL-Dekodierung zu deaktivieren oder zurück zu kodieren, damit der Zielserver bei der Weiterleitung durch nginx genau denselben Pfad erhält? Eine clevere Regel zum Umschreiben von URLs?

Tomasz Nurkiewicz
quelle
Fehler an nginx gemeldet
Tomasz Nurkiewicz

Antworten:

19

Zitat Valentin V. Bartenev (wer sollte die volle Anerkennung für diese Antwort bekommen):

Ein Zitat aus der Dokumentation :

  • Wenn mit URI proxy_pass angegeben wird , wird beim Übergeben einer Anforderung an den Server ein Teil einer normalisierten Anforderungs-URI, die mit dem Speicherort übereinstimmt, durch eine in der Direktive angegebene URI ersetzt

  • Wenn proxy_passangegeben wird , ohne URI , wird eine Anforderung URI an den Server in der gleichen Form übergeben , wie durch einen Client gesendet wird, wenn eine ursprüngliche Anfrage ist

Die richtige Konfiguration in Ihrem Fall wäre:

location /foo {
   proxy_pass http://localhost:8080;
}
Tomasz Nurkiewicz
quelle
8
Ich musste umsteigen http://localhost:8080/, http://localhost:8080falls jemand die gleiche Situation hat wie ich.
Herrtim
4
Warum dekodiert Nginx den URI, bevor er an den Back-End-Server übergeben wird? Wäre es nicht sinnvoller, die URI unangetastet zu lassen?
Schnabeltier
@platypus, es bleibt unangetastet, bis Sie explizit beginnen, die Substitutionen
durchzuführen
2

Beachten Sie, dass die URL-Dekodierung, die in der Dokumentation von nginx allgemein als $uri"Normalisierung" bezeichnet wird , vor dem Back-End-IFF erfolgt:

  • Entweder wird ein beliebiger URI in sich proxy_passselbst angegeben, auch wenn nur der abschließende Schrägstrich für sich allein steht.

  • oder URI wird während der Verarbeitung geändert, z rewrite. B. durch .


Beide Bedingungen sind explizit unter http://nginx.org/r/proxy_pass (Hervorhebung meiner) dokumentiert :

  • Wenn die proxy_passDirektive mit einem URI angegeben wird, wird der Teil einer normalisierten Anforderungs-URI, der mit dem Speicherort übereinstimmt, durch einen in der Direktive angegebenen URI ersetzt , wenn eine Anforderung an den Server übergeben wird

  • Wenn proxy_passangegeben wird , ohne einen URI , wird die Anforderung URI an den Server in der übergebenen gleichen Form wie die von einem Client gesendet , wenn die ursprüngliche Anforderung verarbeitet wird, oder die gesamte normierte Anforderung URI übergeben wird , wenn die Verarbeitung geändert URI


Die Lösung besteht darin, entweder die URI wegzulassen, wie im Fall von OPs, oder in der Tat eine clevere rewriteRegel zu verwenden:

# map `/foo` to `/foo`:
location /foo {
    proxy_pass  http://localhost:8080;  # no URI -- not even just a slash
}

# map `/foo` to `/bar`:
location /foo {
    rewrite  ^  $request_uri;            # get original URI
    rewrite  ^/foo(/.*)  /bar$1  break;  # drop /foo, put /bar
    return 400;   # if the second rewrite won't match
    proxy_pass    http://localhost:8080$uri;
}

Sie können es live in einer verwandten Stapelüberlauf-Antwort sehen , einschließlich der Kontrollgruppe.

cnst
quelle
Die Dokumentation ist hier verwirrend. Beide Formulare enthalten eine URI. Es ist die Pfadkomponente , die in der einen vorhanden ist und in der anderen fehlt.
Michael Hampton
@MichaelHampton, da bin ich anderer Meinung. Der Pfad wird im Allgemeinen als URI bezeichnet. Der Pfad ohne URI enthält also keine URI.
cnst
Ein relativer Pfad allein kann natürlich auch eine gültige URL sein. Der Punkt ist, der Rest ist auch eine gültige URI (zB http://localhost:8080). Wenn Sie anderer Meinung sind, können Sie sich an die Autoren von RFC 3986 wenden.
Michael Hampton
@MichaelHampton Leider scheint es, Schema und Pfad sind obligatorisch, um eine URI zu sein, Autorität, Argumente, Fragment sind optional
Norman Xu