Opened 4 months ago

Closed 4 months ago

Last modified 4 months ago

#2373 closed defect (invalid)

1.23.0 - Spaces in path name result in 400 error when using a proxy server to generate thumbnails

Reported by: robjbrain@… Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.23.x
Keywords: 1.23.0, spaces, %20, 400, thumbnails, proxy Cc: robjbrain@…
uname -a: Linux test 5.15.0-43-generic #46-Ubuntu SMP Tue Jul 12 10:30:17 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.18.0
nginx version: nginx/1.23.0

Description (last modified by Maxim Dounin)

The following server works perfectly on 1.18.0 but on 1.23.0 results in a 400 error for paths with a space in the name e.g.

domain/test dir/image.png = 400 error
domain/testdir/image.png = Works

There are no entries in either "nginx-thumbnails-error.log" or "nginx-thumbnails-localhost-error.log".

There is an entry in "nginx-thumbnails-localhost-access.log" but not in "nginx-thumbnails-access.log".

In requests that resolve (i.e. without spaces) there are entries in both access logs.

When the request fails the user agent is missing from "nginx-thumbnails-localhost-access.log" (no idea if that's relevant).

server {
    # Internal image resizing server.
    server_name localhost;
    listen 8888;

    access_log /var/log/nginx/nginx-thumbnails-localhost-access.log;
    error_log /var/log/nginx/nginx-thumbnails-localhost-error.log error;

    location ~ "^/width/(?<width>\d+)/(?<image>.+)$" {
        alias /home/$image;
        image_filter resize $width -;
        image_filter_jpeg_quality 95;
        image_filter_buffer 8M;
    }

    location ~ "^/height/(?<height>\d+)/(?<image>.+)$" {
        alias /home/$image;
        image_filter resize - $height;
        image_filter_jpeg_quality 95;
        image_filter_buffer 8M;
    }

    location ~ "^/resize/(?<width>\d+)/(?<height>\d+)/(?<image>.*)$" {
        alias /home/$image;
        image_filter resize $width $height;
        image_filter_jpeg_quality 95;
        image_filter_buffer 8M;
    }

    location ~ "^/crop/(?<width>\d+)/(?<height>\d+)/(?<image>.*)$" {
        alias /home/$image;
        image_filter crop $width $height;
        image_filter_jpeg_quality 95;
        image_filter_buffer 8M;
    }
}

proxy_cache_path /tmp/nginx-thumbnails-cache/ levels=1:2 keys_zone=thumbnails:10m inactive=24h max_size=1000m;

server {
    listen 80;
    listen [::]:80;

    server_name ;

    access_log /var/log/nginx/nginx-thumbnails-access.log;
    error_log /var/log/nginx/nginx-thumbnails-error.log error;

    location ~ "^/width/(?<width>\d+)/(?<image>.+)$" {
        # Proxy to internal image resizing server.
        proxy_pass localhost:8888/width/$width/$image;
        proxy_cache thumbnails;
        proxy_cache_valid 200 24h;
    }

    location ~ "^/height/(?<height>\d+)/(?<image>.+)$" {
        # Proxy to internal image resizing server.
        proxy_pass localhost:8888/height/$height/$image;
        proxy_cache thumbnails;
        proxy_cache_valid 200 24h;
    }

    location ~ "^/resize/(?<width>\d+)/(?<height>\d+)/(?<image>.+)$" {
        # Proxy to internal image resizing server.
        proxy_pass localhost:8888/resize/$width/$height/$image;
        proxy_cache thumbnails;
        proxy_cache_valid 200 24h;
    }

    location ~ "^/crop/(?<width>\d+)/(?<height>\d+)/(?<image>.+)$" {
        # Proxy to internal image resizing server.
        proxy_pass localhost:8888/crop/$width/$height/$image;
        proxy_cache thumbnails;
        proxy_cache_valid 200 24h;
    }
}

A test for this error can be created very easily, I did so on an Ubuntu 22 Digital Ocean Droplet.

apt update
apt install nginx
ufw allow 'Nginx Full'
nginx -v

nginx version: nginx/1.18.0

nano /etc/nginx/sites-available/thumbnails
service nginx restart
mkdir /home/testdir
mkdir /home/"test dir"
curl "path/to/image" > /home/testdir/nginx.png
curl "path/to/image" > /home/test dir/nginx.png

Test "/resize/200/200/testdir/nginx.png" and "/resize/200/200/test dir/nginx.png" in the browser and see they both work.

apt-add-repository ppa:ondrej/nginx-mainline -y
apt update
apt install nginx
nginx -v

nginx version: nginx/1.23.0

service nginx restart

Test the two urls in the browser again and you will be able to see that the image directory "test dir" results in a 400 error.

Change History (3)

comment:1 by robjbrain@…, 4 months ago

Please note it should say "proxy_pass http://localhost:8888" but it would not let me through the spam filter due to posting external links.

comment:2 by Maxim Dounin, 4 months ago

Description: modified (diff)
Resolution: invalid
Status: newclosed

That's because spaces are not allowed in request URIs, and since nginx 1.21.1 these are rejected. Quoting CHANGES:

    *) Change: now nginx always returns an error if spaces or control
       characters are used in the request line.

See ticket #196 for details.

Your configuration results in incorrect URIs being used during proxying, as it uses named captures from $uri, which is unescaped, in proxy_pass, which expects all variables to be properly escaped if used with variables.

As far as I can see, in your configuration the most simple fix would be to change all proxy_pass directives to don't use any URI components, that is:

location ~ "/width/(?<width>\d+)/(?<image>.+)$" {
    proxy_pass http://localhost:8888;
    proxy_cache thumbnails;
    proxy_cache_valid 200 24h;
}

This way, nginx will pass URIs from the client request unmodified (and properly escaped), and these match URIs you've been trying to reconstruct with variables.

Hope this helps.

comment:3 by robjbrain@…, 4 months ago

Wow thanks, removing the URI components resolved the issue. I'm not sure why I thought they needed to be there.

Note: See TracTickets for help on using tickets.