Nginx переписать правила 403 ошибка

У меня проблемы с преобразованием файлов.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 с именем include и создал 3 отдельных файла.access с этими правилами перезаписи:

Для первого файла.htaccess, расположенного в корневом каталоге документа, я создал файл в /etc/nginx/ включает в себя 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/, который называется 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 не будут работать должным образом. Кто-нибудь может мне с этим помочь? Я не вижу, что здесь не так.

1 ответ

Решение

Это стандартное поведение 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 читает файлы конфигурации, он сортирует блоки местоположения по 3 типам:

  • Точные блоки местоположения, например 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, чтобы он снова запускал процесс выбора местоположения после перезаписи).

Другие вопросы по тегам