如何限制对 nginx 中动态生成位置的访问?

如何限制对 nginx 中动态生成位置的访问?

我的开发人员希望仅允许局域网内的用户下载某些文件。我说好的,这很简单,然后我对 nginx 配置进行了如下更改:



location /restricteddir/download/file {                                                             
        allow   192.168.0.0/16;                                                              
        allow   10.0.0.0/8;                                                                  
        deny all;                                                                            
    }

好的,从外部我得到了 403,这很好,但是从内部(LAN)我得到了 404。为什么?

我检查了一下,文件的位置在磁盘上不存在。开发人员告诉我,该位置是由 php 动态生成的,因此文件位于 tmp 目录中,但是单击以下链接后:

https://example.com/report/download/file/id/somefile.txt它应该开始下载但却出现 404 错误。

最后的物理位置是/restricteddir/downloadfile/id/somefile.txtphp 生成的。

为了测试,我将位置改为,/restricteddir/download然后访问https://example.com/restricteddir/download也出现 404 错误。

我很困惑,禁用该目录的限制后,一切都正常了,我可以从中下载文件https://example.com/report/download/file/id/somefile.txt并点击https://example.com/report/download/,没有 404。那么错误在哪里?我应该在 nginx 配置中添加什么才能使其正常工作?

编辑1 这是该虚拟主机的完整配置:


#example.com:443
server {
    listen 443 default;
    ssl on;
    ssl_certificate example.crt;
    ssl_certificate_key example.key;
    ssl_session_timeout  15m;
    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers   on;                  
    server_name example.com;
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;



location / {
        root   /sites/public;
        index  index.php;
        if (!-f $request_filename) {
                rewrite ^.*$ /index.php last;
                break;
        }
    }
location /restricteddir/download/file {
       allow   192.168.0.0/16;
       allow   10.0.0.0/8;
       deny all;
    }

#PHP
location ~ \.php$ {        
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;      
        include /fastcgi_params;        
        fastcgi_param  SCRIPT_FILENAME /sites/public$fastcgi_script_name;
    }
}

server {
        listen   80 default;
        server_name example.com;
        access_log off;
        rewrite ^(.*)$ https://example.com$1 permanent;
        }

我在日志中发现了这一点:


2012/08/07 11:55:43 [error] 11121#0: *90 open() "/usr/share/nginx/html/restricteddir/download/file/id/somefile.txt" failed (2: No such file or directory), client: 10.200.2.70, server: example.com, request: "GET /restricteddir/download/file/id/somefile.txt HTTP/1.1", host: "example.com"

所以现在我知道 nginx 在错误的根目录中查找此位置,/usr/share/nginx/html/而不是/sites/public

所以也许我应该这样写:


location /sites/public/restricteddir/download/file {                                                             
        allow   192.168.0.0/16;                                                              
        allow   10.0.0.0/8;                                                                  
        deny all;                                                                            
    }

编辑2

我将根指令移至服务器块,现在在日志中启用位置 /restricteddir/download/file 的限制后,我有:


2012/08/09 10:43:12 [error] 32120#0: *71 open() "/site/public/restricteddir/download/file/id/somefile.txt" failed (2: No such file or directory), client: 10.2.1.120, server: example.com, request: "GET /restricteddir/download/file/id/somefile.txt HTTP/1.1", host: "example.com"
所以现在 nginx 正在正确的地方寻找,但没有找到任何东西。好像这个文件不是由 php 生成的?我正在努力解决它,不知道出了什么问题……这是一个简单的任务,限制位置,为什么这不起作用?

编辑3

这是我的虚拟主机配置现在的样子:


#example.com:443
server {
    listen 443 default;
    ssl on;
    ssl_certificate example.crt;
    ssl_certificate_key example.key;
    ssl_session_timeout  15m;
    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers   on;                  
    server_name example.com;
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;
    root   /sites/public;


location / {
        index  index.php;
        if (!-f $request_filename) {
                rewrite ^.*$ /index.php last;
                break;
        }
    }
location /restricteddir/download/file {
       allow   192.168.0.0/16;
       allow   10.0.0.0/8;
       deny all;
    }

#PHP
location ~ \.php$ {        
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;      
        include /fastcgi_params;        
        fastcgi_param  SCRIPT_FILENAME /sites/public$fastcgi_script_name;
    }
}

server {
        listen   80 default;
        server_name example.com;
        access_log off;
        rewrite ^(.*)$ https://example.com$1 permanent;
        }

因此我只将根指令移入服务器块,之后 nginx 看起来很好但仍然出现 404。我很困惑,因为在我注释掉位置 /restricteddir/download/file 块后一切工作正常,我可以下载文件。

对我来说这并不奇怪,因为它只是简单的限制...为什么启用它后 nginx 找不到该文件...

答案1

两个建议:

  1. root指令移到块中server,这样它将应用于location其后的所有块。这似乎是您的意图。
  2. 请记住位置指令适用于URI不是*文件路径。因此,例如,的想法location /sites/public没有意义。

还有一些其他反馈:

在处理指令时,文件是否物理存在并不重要location,无论如何它们都会匹配。

我发现的另一个不匹配之处是您的日志条目提到了“restricteddir”,但您的“完整配置”帖子没有提到这一点。它反而提到了“报告”目录。

答案2

首先,如果可能的话,我会避免使用以下if代码,因为if 是邪恶的. 改用try_files

location / {
    root   /sites/public;
    index  index.php;
    if (!-f $request_filename) {
            rewrite ^.*$ /index.php last;
            break;
    }
}

这个更好:

location / {
    try_files $uri $uri/ index.php?$args;
}

为了清楚起见,我将移出并root移入该区块:indexlocation /server

server {
    server_name example.com;
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;

    root   /sites/public;
    index  index.php;

这些文件是否完全由 PHP 动态生成,因此不直接存在于文件系统中,因此 nginx 无法在不将请求传递给 PHP 的情况下提供服务?如果是这样,您需要将内容传递给fastcgi_passfastcgi,以便 PHP 可以创建并提供服务,而不是 nginx 尝试提供不存在的内容。所以:

location /report/download/ {
   allow   192.168.0.0/16;
   allow   10.0.0.0/8;
   deny all;
   fastcgi_pass   127.0.0.1:9000;
   fastcgi_index  index.php;      
   include /fastcgi_params;        
   fastcgi_param  SCRIPT_FILENAME /sites/public$fastcgi_script_name;
}

如果文件实际上存在于磁盘上,但位于不同的位置,即请求实际上https://example.com/report/download/file/id/somefile.txt指向磁盘上的位置,/sites/public/restricteddir/download/file/id/somefile.txt并且您希望 nginx 直接为其提供服务而不交给 fastcgi,那么您需要别名指令

location /report/download/ {
   allow   192.168.0.0/16;
   allow   10.0.0.0/8;
   deny all;
   # The actual physical path on disk -
   alias /sites/public/restricteddir/download/;
   # or should this be the following? -
   # alias /restricteddir/download/;
}

最后要检查的是:如果 nginx 和 fastcgi 以不同的用户身份运行,请确保两者都具有正确的操作系统文件权限来读取相关文件。如果 nginx 在正确的位置查找但仍找不到该文件,那么它的所有者和组可能是具有 660 权限的 fastcgi:fastcgi?要么是存在某种缓存,例如open_file_cache在 nginx.conf 中

相关内容