NGINX und automatisches URL encoding

2023-10-28 · christian · nginx, server

Bei dem Versuch einen WebDAV Server mit NGINX aufzusetzen, bin ich mit Anlauf in die Workaround-Hölle gesprungen. Eigentlich war der Gedanke “Joa, verzichten wir Mal auf komplexe Webservices und machen es einfach”. Nun. Hat gut funktioniert.

tl;dr: Die funktionierende Konfiguration mit Kommentaren:

# This NGINX runs behind a reverse proxy, so parse X-Forwarded-For headers
# Directives for setting real_ip/XFF IP address in log files
set_real_ip_from 172.16.0.0/12;
real_ip_header X-Forwarded-For;

server {
    listen 80;
    server_name _;
    root /var/www/public/;

    location / {
        # https://serverfault.com/a/1092384
        # https://www.dimoulis.net/posts/webdav-behind-reverse-proxy/
        # capturing group without name is urlencoded, named capturing group is not.
        # see https://trac.nginx.org/nginx/ticket/348
        set $destination $http_destination;
        if ($destination ~ ^https?://(?<myvar>(.+))$) {
            set $destination "http://$myvar";
            more_set_input_headers "Destination: $destination";
        }

        dav_methods PUT DELETE MKCOL COPY MOVE;
        dav_ext_methods PROPFIND OPTIONS;
        dav_access user:rw;

        client_max_body_size 0;
        create_full_put_path on;
        client_body_temp_path /tmp/;
        autoindex on;
    }
}

Destination Header und Reverse Proxy

Beim Verschieben und Kopieren von Dateien sendet WebDAV einen Destination: https://... Header mit dem Zielpfad. Der Header enthält eine https:// URL, dadurch das der WebDAV Server aber hinter einem Reverse Proxy steht, spricht dieser aber kein TLS.

NGINX weist daher das Request ab:

[error] 6#6: *2 client sent invalid "Destination" header: "https://

Mit more_set_input_headers aus dem Debian Paket libnginx-mod-http-headers-more-filter und ein wenig Regex Magie lässt sich dies aber umgehen.

Im eingehenden Header wird https:// durch http:// ersetzt, bevor das WebDAV Modul mit der Verarbeitung beginnt.

Automatisches URL encoding via Regex

Ein regulärer Ausdruck wie $destination ~ ^https?://(.+)$ erzeugt die Match Group Variable $1, welche die URL aus $destination ohne http:// oder https:// enthält. Leider aber URL encoded. Sprich aus / wird %2F.

Dadurch werden dann auch die Dateien im WebDAV Ordner mit URL kodierten Dateinamen erstellt.

Das ist ein 10 Jahre alter, ungelöster Bug in NGINX. Der Workaround ist die Nutzung von Named Match Groups. In dem Code Block weiter oben wird daher die Match Group als myvar benannt.

Ergebnis ist eine $myvar Variable, welche nicht URL encoded ist.


More


serverless.industries BG by Carl Lender (CC BY 2.0) Imprint & Privacy
4fa348d0 2024-08-31 14:04
Mastodon via chaos.social Mastodon via einbeck.social