yonjah / piwigo_privacy

A small script and nginx configuration to increase the privacy of piwigo gallery
GNU General Public License v2.0
20 stars 8 forks source link

internal server (500) errors on debian jessie #3

Closed mpatey closed 7 years ago

mpatey commented 7 years ago

Hello,

I am trying to make your modifications work on my server, but I am getting very similar results to a previously reported issue ([https://github.com/yonjah/piwigo-privacy/issues/2]). The only difference I can see is that all my photos have been uploaded using the normal web interface.

I get server 500 errors whenever I try to load any image and none of the thumbnails show.

I am running debian jessie with nginx 1.6.2, php5-fpm 5.6.29, and piwigo 2.8.5

My nginx error log has lines like this:

2017/01/13 14:44:01 [error] 8127#0: *319 FastCGI sent in stderr: "PHP message: 400 Invalid request - path 193.[deleted].119" while reading response header from upstream, client: 193.[deleted].119, server: [deleted], request: "GET /_data/i/upload/2016/12/25/20161225210906-31b6cbfc-cu_e260x180.jpg HTTP/1.1", subrequest: "/auth.php", upstream: "fastcgi://unix:/var/run/php5-fpm.sock:", host: "[deleted]", referrer: "https://[deleted]/"
2017/01/13 14:44:01 [error] 8127#0: *319 auth request unexpected status: 400 while sending to client, client: 193.[deleted].119, server: [deleted], request: "GET /_data/i/upload/2016/12/25/20161225210906-31b6cbfc-cu_e260x180.jpg HTTP/1.1", host: "[deleted]", referrer: "https://[deleted]/"

My nginx configuration is as follows:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/website/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/website/privkey.pem;

    server_name [deleted];
    root /var/www/[deleted]/photos;
    index index.html index.htm index.php;

    access_log /var/log/nginx/piwigo.access.log;
    error_log /var/log/nginx/piwigo.error.log;

    location / { try_files $uri $uri/ =404; }
    location ~ /.well-known/ { try_files $uri $uri/ =404; }
    location ~ /\. { access_log off; log_not_found off; deny all; }
    location ~ /~\$ { access_log off; log_not_found off; deny all; }
    # deny PHP execution from subdirectories
    location ~ ^/.+/.*\.php { deny all; }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        # regex to split $uri to $fastcgi_script_name and $fastcgi_path
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        # Check that the PHP script exists before passing it
        try_files $fastcgi_script_name =404;
        # Bypass the fact that try_files resets $fastcgi_path_info
        # see: http://trac.nginx.org/nginx/ticket/321
        set $path_info $fastcgi_path_info;
        fastcgi_param PATH_INFO $path_info;

        fastcgi_index index.php;
        include fastcgi.conf;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }

    # configuration for piwigo-privacy
    location = /auth.php {
        fastcgi_index  auth.php;
        include fastcgi.conf;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }

    location /upload {
        auth_request /auth.php;
        auth_request_set $auth_redirect '/default.png';
            error_page 401 = /auth_401;
    }

    location /_data/i {
        auth_request /auth.php;
        auth_request_set $auth_redirect '/default.png';
            error_page 401 = /auth_401;
    }

    location = /auth_401 {
        if ($auth_redirect) {
            return 302 $auth_redirect;
        }
        return 401;
    }
}

server {
    listen      80;
    listen   [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.[deleted];
    return 301 https://[deleted]$request_uri;
}

server {
    listen      80;
    listen   [::]:80;
    server_name [deleted];
    return 301 https://$server_name$request_uri;
}

Any ideas on what I am doing wrong or how to fix this? Thanks

yonjah commented 7 years ago

I don't think this is similar to #2 your image URL should be recognized. I think it's probably an issue with nginx not passing the right parameters to php-fpm.

Why didn't you include the fastcgi_param as in the nginx configuration file ? Why are you using such an old version of nginx ? I know some distros might ship an old nginx version but since you have to compile nginx anyway it might be better to use a newer version.

mpatey commented 7 years ago

I have included fastcgi.conf. On my system it is the same as fastcgi_param, but also includes the SCRIPT_FILENAME definition:

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

I did not compile nginx. I used the version in the debian jessie repository. Apparently this version supports auth_request:

~$ /usr/sbin/nginx -V
nginx version: nginx/1.6.2
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2' --with-ld-opt=-Wl,-z,relro --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_spdy_module --with-http_sub_module --with-http_xslt_module --with-mail --with-mail_ssl_module --add-module=/build/nginx-AGNHOe/nginx-1.6.2/debian/modules/nginx-auth-pam --add-module=/build/nginx-AGNHOe/nginx-1.6.2/debian/modules/nginx-dav-ext-module --add-module=/build/nginx-AGNHOe/nginx-1.6.2/debian/modules/nginx-echo --add-module=/build/nginx-AGNHOe/nginx-1.6.2/debian/modules/nginx-upstream-fair --add-module=/build/nginx-AGNHOe/nginx-1.6.2/debian/modules/ngx_http_substitutions_filter_module

There is version 1.9.10 in the jessie-backports repository. Do you think this is the problem?

mpatey commented 7 years ago

So I have upgraded to nginx 1.9.10, but the problem is still exactly the same.

I added catch_workers_output = yes to /etc/php5/fpm/pool.d/www.conf to try and get some useful error messages in the php log file, but they don't give too much info. Just lines like the following:

[17-Jan-2017 18:43:05] WARNING: [pool www] child 13802 said into stderr: "NOTICE: PHP message: 400 Invalid request - path [client IP address]" 

Any ideas on how I can dig a bit deeper to find where the problem is?

yonjah commented 7 years ago

From the nginx error it looks like the path cannot being parsed. But the path in the logs seem to be correct so I can only assume it's not being sent to auth.php correctly.

You can try using the following script instead auth.php It will add the path to the error being sent to nginx so you could check that it is correct

<?php 
    function do_error( $code, $str ) {
        error_log($code . ' '.  $str . ' ' . filter_input(INPUT_SERVER, 'REMOTE_ADDR'));
        set_status_header( $code );
        echo $str ;
        exit();
    }   
    $path = filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL);
    do_error(400, "Path is $path"); 

Though this should work with any version that supports auth_request nginx 1.6.x is really old and haven't been supported by nginx in a while so I just wouldn't use it if I have a another option 1.8.x and 1.10.x are the last two stable releases so it's better to use one of them but even 1.9.x would probably be better than 1.6.x

mpatey commented 7 years ago

Running that script I get the following in the nginx error logs:

2017/01/19 09:38:48 [error] 20248#20248: *63 FastCGI sent in stderr: "PHP message: 400 Path is /_data/i/upload/2016/12/25/20161225210906-31b6cbfc-cu_e260x180.jpg [client ip deleted]
PHP message: PHP Fatal error:  Call to undefined function set_status_header() in /var/www/[hostname]/photos/auth.php on line 4" while reading response header from upstream, client: [client ip deleted], server: [hostname], request: "GET /_data/i/upload/2016/12/25/20161225210906-31b6cbfc-cu_e260x180.jpg HTTP/1.1", subrequest: "/auth.php", upstream: "fastcgi://unix:/var/run/php5-fpm.sock:", host: "[hostname]", referrer: "https://[hostname]/"
2017/01/19 09:38:48 [error] 20248#20248: *63 auth request unexpected status: 500 while sending to client, client: [client ip deleted], server: [hostname], request: "GET /_data/i/upload/2016/12/25/20161225210906-31b6cbfc-cu_e260x180.jpg HTTP/1.1", host: "[hostname]", referrer: "https://[hostname]/"

So nginx is sending the path?

set_status_header is apparently undefined . Is that a piwigo function?

mpatey commented 7 years ago

Hi,

So I realised that I needed to include common.inc.php to make your script work.

I am messages like this:

"PHP message: 200 Path is /_data/i/upload/2016/12/24/20161224015905-abf01be0-cu_e260x180.jpg **client-ip"

So is the problem that the server is for some reason adding the client ip to the path?

I have tried changing the fastcgi_param REQUEST_URI $request_uri; definition to other things, but the ip address is still appended.

yonjah commented 7 years ago

Ok it seem like there was an issue with an update I made to get_file_from_path function. It should be fixed now so update auth.php and see if it works

mpatey commented 7 years ago

It's working now. Thanks for the update.

I have a small suggestion for improvement. As I understand it, your code returns 401 if the file name and path passed matches a pattern for a valid piwigo image and either the user does not have permission to view that file or the file does not exist. If the file name passed doesn't match the regular expression then it returns 400.

Nginx's auth_request module only looks for a 2xx, 401 or 403 coming back from auth.php - anything else is an error and hence the 500 errors that I have been seeing. Would it be better to return either 200 (so that nginx will try to serve the file and give a 404 not found (since it's an invalid path) or to return 401 (thus making an invalid pathname indistinguishable from a missing file or a file that the user is not allowed to access)?

Thanks for your work.

yonjah commented 7 years ago

@mpatey Thank you for your feedback.

This is still more of a proof of concept than a working solution. I don't think this is a major issue since the path structure is not something that has to be kept secret If the path is invalid for some reason it is probably a configuration / code error and we want to notice it as soon as possible.

I guess once this will be in a bit more stable state it might be possible to add a silent mode that will either return 401 or 200 code

yonjah commented 7 years ago

@mpatey I rewrote most of the logic of this plugin and fixed some issues. It is not yet on the master branch but if you want you can check it here - https://github.com/yonjah/piwigo_privacy/tree/plugin-alpha