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, процесс выбора местоположения выглядит следующим образом:
- Если найден точный блок местоположения, соответствующий URI, nginx прекращает поиск других блоков местоположения и выполняет этот запрос.
- Если нет, nginx будет искать блок с самым длинным совпадающим префиксом местоположения и запоминает его перед переходом к следующему шагу.
- Затем nginx последовательно проверяет блоки размещения, содержащие регулярные выражения. Первый соответствующий будет использоваться для обслуживания запроса.
- Если на предыдущем шаге ничего не было найдено, то 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, чтобы он снова запускал процесс выбора местоположения после перезаписи).