Сначала правило, которое работает:
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. - [Ж, Л]
Предположим, что ваш 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. - [Ж, Л]
Как вы предполагаете, это не противоречит приведенным выше правилам, оно соответствует чему-либо, кроме /
и /index.php
(при использовании в .htaccess
]). Таким образом, это запрещает доступ ко всем другим URL-адресам, независимо от метода запроса. (Как упоминалось выше, похоже, это первое правило, которое запускало 403 при доступе к http://example.com/
.) Если вы включили исключение для ваших документов об ошибках, как указано выше, тогда вы не нужно добавлять дополнительное условие.