Назад | Перейти на главную страницу

Как ограничить доступ к динамически генерируемому местоположению в 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/download так file/id/somefile.txt генерируется php.

Для тестирования я изменил локацию на /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

Я переместил корневую директиву в блок сервера и теперь в журналах после включения ограничения для location / limiteddir / 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"
So now nginx is looking in right place but doesn't find enything. Like this file was not generated by php? I'm strugling with it and have no idea what is wront... Thats a simple task restrcit location why this doesn't work ?

РЕДАКТИРОВАТЬ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. Я запутался, потому что после того, как я закомментировал блок location / limiteddir / download / file, все работает нормально, и я могу загрузить файл .

Для меня это не очень странно, потому что это единственное простое ограничение ... почему после включения nginx не смог найти этот файл ...

Два предложения:

  1. Переместите root директива в server блок, поэтому он будет применяться ко всем location блоки, которые следуют за ним. Похоже, это ваше намерение.
  2. Имейте в виду, что директива местоположения относится к URI не * пути к файлам. Так, например, идея location /sites/public не имеет смысла.

И еще несколько отзывов:

Вопрос о том, существуют ли файлы физически или нет, не имеет значения при обработке. location директивы, они будут совпадать независимо.

Еще одно несоответствие, которое я вижу, заключается в том, что ваша запись в журнале относится к "ограниченному каталогу", но в вашем сообщении "полная конфигурация" об этом не упоминается. Вместо этого он упоминает каталог "report".

Во-первых, я бы избегал следующих 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 и index снаружи location / и в 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_pass в fastcgi, чтобы 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 ищет в нужном месте, но все равно не может найти файл, возможно, его владелец и группа - fastcgi: fastcgi с разрешениями 660? Либо это, либо происходит какое-то кеширование, например open_file_cache в nginx.conf