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

Ошибка 403 правил перезаписи Nginx

У меня проблемы с преобразованием файлов .htaccess в nginx. У меня 3 файла .htaccess. Первый файл .htaccess находится в корне документа и выглядит следующим образом:

Options +FollowSymLinks
RewriteEngine On
RewriteRule ^img-(.*)\.html img.php?id=$1 [L]
RewriteRule ^slide-(.*)\.html slider.php?id=$1 [L]
RewriteRule ^page-(.*)\.html page.php?name=$1 [L]
RewriteRule ^contact\.html$ contact.php [QSA,L,NC]

Второй файл .htaccess находится в папке с именем upload:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+\.)?foo\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*\.(jpe?g|gif|bmp|png)$ nohotlink.gif [L]
<Files ~ "\.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$">
  order allow,deny
  deny from all
</Files>

И третий и последний файл .htaccess находится в подкаталоге папки загрузки с именем "small":

RewriteEngine Off

Теперь я создал папку в / etc / nginx под названием includes и сделал 3 отдельных файла .access с этими правилами перезаписи:

Для первого файла .htaccess, расположенного в корневом каталоге документа, я создал файл в / etc / nginx / includes с именем root.access. В этом файле у меня есть:

# nginx configuration 

location /img { 
rewrite ^/img-(.*)\.html /img.php?id=$1 break; 
} 
location /slide { 
    rewrite ^/slide-(.*)\.html /slider.php?id=$1 break; 
} 
location /page { 
    rewrite ^/page-(.*)\.html /page.php?name=$1 break; 
} 
location /contact { 
    rewrite ^/contact\.html$ /contact.php break; 
}

Для второго файла, находящегося в папке «upload», я создал файл в / etc / nginx / includes под названием upload.access. Этот файл содержит следующее:

# nginx configuration 

location /upload { 
if ($http_referer !~ "^http://(.+\.)?foo\.com/"){ 
rewrite .*\.(jpe?g|gif|bmp|png)$ /nohotlink.gif break; 
} 
} 
location ~ \.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ { 
deny all; 
}

А для третьего и последнего файла я создал файл в / etc / nginx / с именами small.access. Содержимое этого файла следующее:

# nginx configuration 

location /upload/small { 
}

В файле конфигурации серверного блока у меня есть:

 location / {
              try_files $uri $uri/ /index.php;
              include /etc/nginx/includes/root.access;
     }

 location /upload {
              include /etc/nginx/includes/upload.access;
     }

 location /upload/small {
              include /etc/nginx/includes/small.access;
     }

Теперь с этой конфигурацией при попытке сайта я получаю 403 ошибки. Отчеты журнала ошибок Nginx:

[error] 18156#0: *7 access forbidden by rule, client: 111.**.**.**, server: foo.com, request: "POST /upload.php HTTP/1.1", host: "foo.com", referrer: "http://foo.com/"

Теперь под apache все работает без проблем. Но я не могу понять, почему я получаю ошибку 403. Я также обеспокоен тем, что правила перезаписи, как я их сформулировал, помимо ошибки 403, вообще не будут работать должным образом. Кто-нибудь может мне с этим помочь? Я не вижу, что здесь не так.

Это стандартное поведение nginx для этой части вашей конфигурации:

location /upload { 

    if ($http_referer !~ "^http://(.+\.)?foo\.com/"){ 
        rewrite .*\.(jpe?g|gif|bmp|png)$ /nohotlink.gif break; 
    } 

    location ~ \.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ { 
        deny all; 
    }

}

Зачем?

Позвольте мне пояснить, как работают локации: когда nginx читает файлы конфигурации, он сортирует блоки локаций по трем типам:

  • Точный блоки местоположения, например location = /upload { }
  • С префиксом блоки местоположения, например location /upload { }
  • Блоки локации, содержащие регулярные выражения например location ~ /upload { }

Как только запрос приходит в nginx, процесс выбора местоположения выглядит следующим образом:

  1. Если найден точный блок местоположения, соответствующий URI, nginx прекращает поиск других блоков местоположения и обслуживает этот запрос.
  2. Если нет, nginx будет искать самый длинный совпадающий блок с префиксом местоположения и запомнит его перед переходом к следующему шагу.
  3. Затем nginx последовательно проверяет блоки местоположения, содержащие регулярные выражения. Первый из подходящих будет использоваться для обслуживания запроса.
  4. Если на предыдущем шаге ничего не было найдено, то nginx будет использовать префиксный блок местоположения шага 2 для обслуживания запроса. Если ничего не найдено, может произойти несколько вещей, но это не по теме.

Итак, в вашем случае блок местоположения, соответствующий .php расширение имеет приоритет над блоком местоположения, соответствующим /upload часть URI.

редактировать : Пояснение к решению, добавлено альтернативное решение.

Используя ^~ вы можете указать nginx изменить его поведение на шаге 2, чтобы он немедленно использовал совпадающее префиксное местоположение, минуя поиск местоположений по регулярным выражениям. Итак, у вас есть 2 решения:

Решение 1 :

upload.access:

if ($http_referer !~ '^http://(.+\.)?foo\.com/') { 
    rewrite '.*\.(jpe?g|gif|bmp|png)$' '/upload/nohotlink.gif' break; 
} 

if ($uri ~ '\.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$') {
    return 403; 
}

тот же серверный блок

Решение 2 :

upload.access:

if ($http_referer !~ '^http://(.+\.)?foo\.com/') { 
    rewrite '.*\.(jpe?g|gif|bmp|png)$' '/upload/nohotlink.gif' break; 
} 

location ~ \.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ {
    deny all;
}

серверный блок:

 location ^~ /upload {
     include /etc/nginx/includes/upload.access;
 }

Теперь ваша текущая конфигурация ни к чему не приведет, если вы не настроите место для пересылки обработки файла php: проверьте nginx модуль fastcgi. Затем вам нужно будет изменить правила перезаписи в файле root.access, чтобы они не разрешались в контексте текущего местоположения (т.е. создать одно уникальное резервное местоположение и изменить break к last чтобы указать nginx снова запустить процесс выбора местоположения после перезаписи).