Невозможно игнорировать mod переписать внутренние перенаправления с флагом NS

я определил пару mod_rewrite правила .htaccess файл, один, чтобы переписать путь URL из /rwtest/source.html до /rwtest/target.html, а другой запретить прямой доступ к /rwtest/target.html. То есть, все пользователи, желающие увидеть содержимое /rwtest/target.html введите /rwtest/source.html в их строке URL.

я пытался использовать NS флаг в правиле forbid для предотвращения перезаписи URL-адресов также запрещен, но, похоже, этот флаг не различает первый запрос и внутренний перенаправлять. Казалось бы, что NS должен делать свою работу, но я уверен, что я что-то неправильно понял.

может кто-нибудь прояснить это поведение? Что именно делает это внутреннее перенаправление не внутренним подреберьем, что NS флаг может игнорировать?

детали:

вот мой полный :

Options +FollowSymLinks -Multiviews

RewriteEngine on
RewriteBase /rwtest

# Forbid rule. Prohibit direct access to target.html. Note the NS flag.
RewriteRule ^target.html$ - [F,NS]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html

я запускаю Apache 2.4.9 в Windows 7 x64, но я наблюдал подобное поведение на Apache 2.4.3 в Linux. Вот вывод журнала для запрос /rwtest/source.html.

[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] strip per-dir prefix: C:/Apache24/htdocs/rwtest/source.html -> source.html
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] applying pattern '^target.html$' to uri 'source.html'
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] strip per-dir prefix: C:/Apache24/htdocs/rwtest/source.html -> source.html
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] applying pattern '^source.html$' to uri 'source.html'
[rewrite:trace2] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] rewrite 'source.html' -> 'target.html'
[rewrite:trace3] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] add per-dir prefix: target.html -> C:/Apache24/htdocs/rwtest/target.html
[rewrite:trace2] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] trying to replace prefix C:/Apache24/htdocs/rwtest/ with /rwtest
[rewrite:trace5] [rid#20b6200/initial] strip matching prefix: C:/Apache24/htdocs/rwtest/target.html -> target.html
[rewrite:trace4] [rid#20b6200/initial] add subst prefix: target.html -> /rwtest/target.html
[rewrite:trace1] [rid#20b6200/initial] [perdir C:/Apache24/htdocs/rwtest/] internal redirect with /rwtest/target.html [INTERNAL REDIRECT]
[rewrite:trace3] [rid#20ba360/initial/redir#1] [perdir C:/Apache24/htdocs/rwtest/] strip per-dir prefix: C:/Apache24/htdocs/rwtest/target.html -> target.html
[rewrite:trace3] [rid#20ba360/initial/redir#1] [perdir C:/Apache24/htdocs/rwtest/] applying pattern '^target.html$' to uri 'target.html'
[rewrite:trace2] [rid#20ba360/initial/redir#1] [perdir C:/Apache24/htdocs/rwtest/] forcing responsecode 403 for C:/Apache24/htdocs/rwtest/target.html

решения

я опубликовал несколько обходных путей ниже.

1 ответов


есть несколько обходных путей для этого, каждый со своими плюсами и минусами. Как отказ от ответственности, я только протестировал их в .htaccess контексте.


Способ 1. Проверьте наличие пустого REDIRECT_STATUS

добавить RewriteCond проверка, чтобы увидеть, если %{ENV:REDIRECT_STATUS} пусто. Если он пуст, то текущий запрос не является внутренним перенаправлением.

плюсы

  • самый простой способ определить внутренний перенаправлять.

минусы

  • отсутствие документации. На странице Пользовательские Ответы На Ошибки кратко упоминает эту переменную:

    REDIRECT_ переменные среды создаются из переменных среды, которые существовали до перенаправления. Они переименованы с REDIRECT_ префикс, т. е. HTTP_USER_AGENT становится REDIRECT_HTTP_USER_AGENT. REDIRECT_URL, REDIRECT_STATUS и REDIRECT_QUERY_STRING гарантированы, что будут установлены, и другие заголовки будут только если они существовали до возникновения ошибки.

    я пробовал все другие REDIRECT_ переменная RewriteCond, но все они, кроме REDIRECT_STATUS были пусты для внутренних редиректов. Почему?--12--> особенный в mod_rewrite остается загадкой.

пример

# Forbid rule. Prohibit direct access to target.html.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^target.html$ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html

кредиты для этого подхода перейти к URL переписать: внутренняя ошибка сервера.


Способ 2. Правило остановки перезаписи обработка с конца

в отличие от L флаг END останавливает переписывать правила даже для внутренних перенаправлений.

плюсы

  • простой. Просто дополнительный флаг.

минусы

  • не дает вам достаточно контроля над тем, какие правила обрабатывать и какие пропускать.

пример

# Forbid rule. Prohibit direct access to target.html.
RewriteRule ^target.html$ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html [END]

для получения дополнительной информации см. конец флаг.


Способ 3. Сопоставьте с исходным URL-адресом в THE_REQUEST

%{THE_REQUEST}

полная строка HTTP-запроса, отправленная браузером на сервер (например, " GET / index.html HTTP / 1.1").

THE_REQUEST не изменяется с внутренними перенаправлениями, поэтому вы можете сопоставить его.

плюсы

  • может использоваться для сопоставления с исходным URL-адресом даже во втором раунде Обработка URL-адрес.

минусы

  • значительно сложнее, чем другие подходы. Заставляет использовать RewriteCond где только один RewriteRule было бы достаточно.

  • соответствует полному URL-адресу, который не был unescaped (декодирован), в отличие от большинства других переменных.

  • неудобно использовать в несколько RewriteRules. RewriteConds можно скопировать над каждым RewriteRule или значение можно экспортировать в переменную среды (см. Пример). Обе хакерские альтернативы.

пример

# Forbid rule. Prohibit direct access to target.html.
RewriteCond %{THE_REQUEST} "^[^ ]+ ([^ ?]*)"  # extract path from request line
RewriteCond %1 ^/rwtest/target.html$
RewriteRule ^ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteRule ^source.html$ target.html

или экспортируйте путь к переменной среды и используйте его в нескольких RewriteRules.

# Extract the original URL and save it to ORIG_URL.
RewriteCond %{THE_REQUEST} "^[^ ]+ ([^ ?]*)"  # extract path from request line
RewriteRule ^ - [E=ORIG_URL:%1]

# Forbid rule. Prohibit direct access to target.html.
RewriteCond %{ENV:ORIG_URL} ^/rwtest/target.html$
RewriteRule ^ - [F]

# Rewrite rule. Rewrite source.html to target.html.
RewriteCond %{ENV:ORIG_URL} ^/rwtest/source.html$
RewriteRule ^ target.html