Указать всем на index.php конфликт с частным каталогом


Вот структура моего сайта (корневая):

private
public
.htaccess
index.php

Файл htaccess содержит:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /index.php [L]

Сказав это, все URL-адреса указывают на index.php

В папке private У меня также есть файл .htaccess, который содержит:

Order Deny,Allow
Deny from all

Проблема в том, что http://www.example.com/private/ выбрасывает 403, а я этого не хочу. Возможно, я захочу использовать http://www.example.com/private/ местоположение, чтобы показать что-то на своем веб-сайте.

Я должен упомянуть, что я не хочу прикасаться к файлу .htaccess из папки private в любом путь.

Итак, я ищу способ установить некоторые правила в основном файле .htaccess.

Как мне это сделать? Возможно ли это?

Редактировать: Подробнее о моей проблеме.

Представьте себе CMS с общей папкой и личной папкой. Папка private даже не принадлежит корневому веб-серверу. Он не должен находиться в public_html, www или других общедоступных папках. Ну, говоря о CMS, не все пользователи понимают это, и они все еще могут хранить папку private в public_html.

С учетом сказанного, папка private должна содержать файл htaccess, который запрещает доступ к файлам через браузер (пример www.example.com/private/internal_script.php).

Но я все еще хочу иметь возможность отображать контент в браузере для www.example.com/private/ местоположения.

Прямо сейчас я могу размещать любой контент, какой захочу, по любому URL-адресу. Это связано с основным файлом htaccess, который позволяет мне выбирать, что показывать с помощью PHP. Но я все еще не могу отправлять контент по URL www.example.com/private/, потому что это указывает на частный каталог, который содержит htaccess с запретом доступа.

www.example.com/hello/ может быть категория, статья и т. Д.

www.example.com/awesome/ может быть категория, статья и т. Д.

www.example.com/private/ не может быть ничего. Я получаю 403...

Author: Andrei, 2021-01-15

2 answers

Это технически возможно, однако существует другое "предпочтительное" решение для "CMS с папкой public и папкой private" (см. Ниже).

Чтобы кратко изложить требования:

  1. Разрешить маршрутизацию запросов для /private/ или /private/<something> (где <something> не является физическим файлом в подкаталоге /private) через фронт-контроллер (т.е. /index.php в корневом каталоге). Как и любой другой (не файловый) URL-адрес.
  2. Любые HTTP-запросы для /private/<actual-file> должны быть заблокированы (403 Запрещено), в том виде, в каком они есть в настоящее время. (ОБНОВЛЕНИЕ: Хотя это не требуется, кажется, что это должно быть переписано на фронт-контроллер, как в #1)
  3. Можно изменить только родительский файл .htaccess в корневом каталоге документа.

Нам в основном нужно "переопределить" ответ 403 Forbidden для защищенного подкаталога, когда запрашивается либо сам каталог, либо не файл в этом подкаталоге.

Обычно директивы в подкаталоге .htaccess директивы переопределения файла в родительском файле .htaccess, поэтому нам нужно изменить порядок обработки и убедиться, что необходимые "переопределяющие" директивы в родительском файле .htaccess обрабатываются позже . Это может быть достигнуто путем упаковки директив в контейнер <Files> (или <FilesMatch>) или в блок <If> с использованием выражения Apache .

Однако дополнительным осложнением в данном конкретном случае является использование устаревшего (Apache 2.2 и более ранних версий) Order и Deny директивы в защищенном подкаталоге. (В Apache 2.4, который, как я полагаю, вы используете, вместо этого вы должны использовать директиву single Require all denied.) Чтобы "переопределить" директивы авторизации в подкаталоге, вы должны использовать тот же метод авторизации. (Именно поэтому в документах Apache подчеркивается, что вам следует избегать смешивания двух (старых и новых) методов авторизации. Старые/устаревшие директивы предоставляются только для обратной совместимости и должны быть перенесены - полностью - при первой же возможности. Будучи официально устаревшими, они будут полностью удалены в будущих версиях Apache.)

Итак, вы можете сделать что-то вроде следующего в корневом файле .htaccess. Порядок директив строго не имеет значения, вы можете разместить его до или после вашего фронт-контроллера mod_rewrite, однако было бы логичнее иметь его до.

# For any request that starts "/private" and does not map to a physical file then...
<If "%{REQUEST_URI} =~ m#^/private# && !-f %{REQUEST_FILENAME}">
    DirectoryIndex disabled
    DirectorySlash Off

    # If using Apache 2.4 directives...
    #Require all granted

    # If using old Apache 2.2 directives in the subdirectory then need to use the same here...
    Order Deny,Allow
    Allow from all
</If>

Необходимо отключить DirectoryIndex для подкаталога, чтобы предотвратить попытку mod_dir обслуживать индексный документ (например, index.php) при запросе чистого каталога. Если DirectoryIndex включен, то... если индексный документ существует, то mod_dir выдает внутренний подзапрос, который затем блокируется, и URL-путь недоступен для вашей CMS. Если индексный документ не существует, то mod_dir блокирует запрос, и URL-путь недоступен для вашей CMS.

DirectorySlash Off требуется только в том случае, если вы хотите иметь доступ к /private без задней косой черты. Обычно mod_dir добавляет завершающую косую черту с перенаправлением 301, так как /private является физическим каталогом.

ОБНОВЛЕНИЕ: С тех пор я понял, что вам не нужен #2 выше, и вы хотите просто переписать /private/<anything> на /index.php (ваш фронт-контроллер), даже если в противном случае он был бы сопоставлен с реальным файлом. В этом случае ваше измененное предложение выглядит хорошо:

<If "%{REQUEST_URI} =~ m#^/private#">
Order Deny,Allow
Allow from all
RewriteRule ^ /index.php [L]
</If>

Он повторяет перезапись на фронт-контроллер (который все еще присутствует позже в файле .htaccess), но это необходимо для переопределения DirectoryIndex и для принудительной перезаписи любых запросов на физические файлы в подкаталоге /private на фронт-контроллер (чтобы быть недоступным).

Я не уверен, что делает =~ m#^/private#, но я полагаю, что он проверяет, начинается ли URL-адрес с "/private". Мне также интересно, каков эффект, если URL-адрес начинается с /privatesomething

Да, он проверяет, что запрошенный URL-путь начинается /private. =~ является регулярным выражением оператор сравнения и m#<regex># - это альтернативный синтаксис для регулярного выражения. Вы также можете использовать /<regex>/ (обычные разделители косой черты), но это, естественно, создает проблемы при проверке URL-адресов.

Вы не можете только проверить, что URL-адрес начинается /private/ (с завершающей косой черты), так как запрос на /private (без завершающей косой черты) вызовет ответ 403 до того, как mod_dir добавит косую черту.

/privatesomething также попадется на это, но это не должно иметь значения, так как вы только позволяете получите доступ и перепишите запрос - это то, что вы все равно хотите сделать.

Однако, если у вас есть физические файлы в корневом каталоге, которые не должны передаваться в CMS и обслуживаться напрямую, например/privatesomething.jpg, то это действительно будет проблемой с вышеуказанным регулярным выражением. Это можно решить, изменив регулярное выражение так, чтобы оно соответствовало либо /private или /private/something, но не /privatesomething. Например:

<If "%{REQUEST_URI} =~ m#^/private($|/)#">

CMS с папкой public и папкой private

Как правило, при отправке CMS с помощью /public и /private подкаталог на том же уровне, то намерение, если у вас есть доступ к конфигурации сервера, состоит в том, чтобы изменить DocumentRoot сервера, чтобы указать на подкаталог /public. ИЛИ, если у вас нет доступа к конфигурации сервера, то безоговорочно перепишите запрос с помощью mod_rewrite в подкаталог /public. И иметь дополнительный файл .htaccess в подкаталоге /public, содержащий ваш шаблон фронт-контроллера. (Все необходимые файлы должны быть поставляется с CMS - ничего не нужно редактировать вручную, кроме, возможно, комментария, если у вас есть доступ к конфигурации сервера.)

Этот метод скрывает путь к файлу /public от видимого URL-адреса (что является намерением) и, естественно, решает проблему, обсуждавшуюся выше, с конфликтом URL-адреса с защищенным подкаталогом /private.

Например, (если не изменять DocumentRoot в конфигурации сервера), то в корневом файле .htaccess:

RewriteEngine On

# Unconditionally rewrite all requests to the "/public" subdirectory
RewriteRule ^ /public%{REQUEST_URI} [L]

Тогда в /public/.htaccess у вас есть ваш фронт-контроллер:

RewriteEngine On

# CMS front-controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

Обратите внимание на отсутствие косой черты в начале RewriteRule подстановка строка. Здесь должно быть index.php, а не /index.php.

 2
Author: MrWhite, 2021-01-17 02:04:45

Я немного поиграл с этим, и я не верю, что это возможно - по крайней мере, не в главном файле .htaccess, не нарушая ограничений сервера.

Я полагаю, что можно переопределить поведение по умолчанию, изменив файл конфигурации apache.

Возможно, имеет смысл переместить вашу личную конфигурацию выше корневого каталога документа (я предполагаю, что вы используете ее для включения контента с помощью чтения с PHP или аналогичного, или просто не имеете доступа к веб-серверу) - в этом случае вы можете создать еще один частный подкаталог в вашем корневом каталоге документов, который доступен через веб-сервер.

 1
Author: davidgo, 2021-01-15 20:31:40