Почему RewriteCond% {REQUEST_URI} мешает второму условию NOT?

1

Сначала правило, которое работает:

DirectoryIndex index.php
ErrorDocument 403 /form.html

RewriteCond %{REQUEST_URI} ^/index\.php$
RewriteCond %{REQUEST_METHOD} !POST
RewriteRule . - [F,L]

Это означает http://example.comи http://example.com/index.phpможет быть открыт только через POST.

Теперь проблема

Я добавил этот дополнительный набор правил:

RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule . - [F,L]

Теперь я отправляю POST снова, http://example.comно получаю эту ошибку:

Forbidden

You don't have permission to access / on this server.
Additionally, a 500 Internal Server Error error was encountered while trying to use an ErrorDocument to handle the request.

Это не имеет смысла, потому что правило НЕ должно отлавливать запросы при index.phpотправке 403, но хорошо, я расширил второе правило следующим образом:

RewriteCond %{REQUEST_URI} !^/form\.html$
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule . - [F,L]

И отправка снова POST на http://example.com не возвращает 500, но я все равно получаю 403 ?!

Обновление 1
Если я удаляю первый набор правил, второй работает один, как и ожидалось. Это означает только http://example.com, http://example.com/index.phpи http://example.com/form.htmlмогут быть доступны.

Обновление 2
Если я использую оба набора правил и отправляю свой POST, http://example.com/index.phpя не получаю никаких ошибок ?!

Так что правила мешают, только если я отправил POST на корневой URL. Но почему?

mgutt
источник

Ответы:

0
RewriteCond %{REQUEST_URI} ^/index\.php$
RewriteCond %{REQUEST_METHOD} !POST
RewriteRule . - [F,L]

Предполагая, что ваше значение DirectoryIndexустановлено на, index.phpи у вас нет других директив, тогда это может показаться вашим первым блоком правил, который приводит к 403 Запрещенному при доступе http://example.com/. Выше разрешены только прямые запросы POST /index.php.

RewriteRule Модели (одна точка) в приведенном выше предотвращает правило обрабатывается на всех для запросов к http://example.com/. Затем mod_dir инициирует внутренний подзапрос к /index.php. Обратите внимание, что этот подзапрос фактически отображается как внутренний запрос GET (именно так устанавливается REQUEST_METHODпеременная сервера), поэтому вышеуказанное условие ( !POST) выполнено успешно и запрос в конечном итоге запрещен.

Было бы предпочтительнее , чтобы canonicalise запроса и внешнее перенаправление (308 - постоянное перенаправления сохранения метод запроса) любой запрос /index.phpна /. Затем вы можете сосредоточиться на сопоставлении просто /и можете игнорировать подзапросы.

# Exception for error document (before other directives)
RewriteRule ^form\.html$ - [L]

# Canonicalise URL and remove "index.php" if requested
RewriteRule %{REDIRECT_STATUS} ^$
RewriteRule ^index\.php$ / [R=308,L]

# Only allow POST requests to the document root
RewriteCond %{REQUEST_METHOD} !POST
RewriteRule ^$ - [F]

(Нет необходимости в Lфлаге, когда Fиспользуется. LПодразумевается.)

Убедитесь, что кэш браузера очищен перед тестированием. (Может быть предпочтительнее тестировать с R=307(временными) перенаправлениями, чтобы избежать кеша.)

RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule . - [F,L]

Как вы предполагаете, это не противоречит приведенным выше правилам, оно соответствует чему-либо, кроме /и /index.php(при использовании в .htaccess). Таким образом, это запрещает доступ ко всем другим URL-адресам независимо от метода запроса. (Как упомянуто выше, это, кажется, первое правило, которое инициировало 403 при доступе http://example.com/.) Если вы включите исключение для ваших сообщений об ошибках, как описано выше, тогда вам не нужно добавлять дополнительное условие.

MrWhite
источник
Первая часть вашего ответа относительно единой точки и внутреннего GET неверна. Как я уже писал в первом предложении, это правило (само по себе) работает без проблем. PS Я добавил настройку DirectoryIndex, чтобы никто не думал об этом.
mgutt