Сначала правило, которое работает:
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. Но почему?
RewriteCond %{REQUEST_URI} ^/index\.php$ RewriteCond %{REQUEST_METHOD} !POST RewriteRule . - [F,L]
Предполагая, что ваш DirectoryIndex
установлен на index.php
и у вас нет других директив, тогда это будет ваш первый блок правил, который приводит к 403 Forbidden при доступе http://example.com/
. Вышеупомянутое позволяет только прямые запросы POST к /index.php
.
В RewriteRule
шаблон (одна точка) в приведенном выше примере запрещает обработку правила для запросов к http://example.com/
. mod_dir затем инициирует внутренний подзапрос на /index.php
. Обратите внимание, что этот подзапрос на самом деле выглядит как внутренний запрос GET (что и является REQUEST_METHOD
переменная сервера устанавливается в), поэтому указанное выше условие (!POST
) успешно, и запрос в конечном итоге запрещен.
Было бы предпочтительнее канонизировать запрос и перенаправить извне (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/
.) Если вы включили исключение для ваших документов об ошибках, как указано выше, вам не нужно добавлять дополнительное условие.