Почему index.php находится в папке public, а не в общей папке?

3 Апреля 2022 (ред)

Если вы знакомы со структурой сайта libArea, то знаете, что файл index.php находится в папке public. Это хорошая идея держаться index.php за пределами корневого каталога вашего проекта:

Структура LibArea

Публичный каталог (public)

Публичный каталог (/public) является домом для всех общедоступных и статических файлов вашего приложения, включая изображения, таблицы стилей и файлы JavaScript. Там же находится index.php.

Другие фреймворки и приложения PHP могут использовать другой подход и добавлять index.php файл непосредственно в root каталог. Пока вы направляете сервер в «общедоступный» каталог, содержащий index.php файл, сайт должен отображаться так, как ожидалось.

В LibArea файл index.php находится в public папке с другими «безопасными для просмотра» ресурсами, такими как css, js, изображения и т.д. Это способствует хорошей практике безопасности, чтобы общедоступные файлы были общедоступными, а частные файлы — частными.

Поощряйте надлежащие методы обеспечения безопасности, чтобы общедоступные файлы были общедоступными, а другие, нет.

Но как насчет приложений, которые добавляют index.php в корень?

Есть много популярных веб-приложений, которые не следуют этой структуре и предоставляют index.php в корневом каталоге.

Существует (если обобщать и упрощать) два подхода.

Использование папки /public — это подход к безопасности с использованием «белого списка», означающий, что все запрещено, кроме того, что находится в белом списке (все в общей папке).

Неиспользование папки /public — это подход к безопасности с использованием «черного списка», означающий, что разрешено все, кроме того, что занесено в черный список (правила, определенные в файле конфигурации вашего веб-сервера).

LibArea использует подход «белого списка» к веб-безопасности. Это сделано потому, что мы считаем, что держать весь наш системный код в корневой папке — не очень хорошая идея. (Аналогично обстоят дела и с Content Security Policy).

Настройка веб-сервера (для локальной отладки)

Пример конфигурации для XAMPP, PHP 8.1.2, httpd-xampp.conf:

<VirtualHost *:80>
    ServerAdmin webmaster@lib.loc
        DocumentRoot "d:/xampp/htdocs/lib.loc/public"
        ServerName lib.loc
    ServerAlias www.lib.loc
    ErrorLog "d:/xampp/htdocs/lib.loc/error.log"
        CustomLog "d:/xampp/htdocs/lib.loc/access.log"
    <Directory "d:/xampp/htdocs/lib.loc/public">
        Require all granted
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

Или для пакета: XAMPP для Windows 8.1.4 (PHP 8.1.4), файл (httpd-vhosts.conf):

<VirtualHost *:80>
    ServerAdmin webmaster@lib.loc
    DocumentRoot "D:/xampp/htdocs/lib.loc/public"
    ServerName lib.loc
</VirtualHost>

Больше информации: https://libarea.com/ru/web-server-configuration/

P.S. обычно техническая поддержка хостинга (если вы объясните ей ситуацию по поводу public) знает о чем разговор и довольно охотно поможет сделать подобающие настройки. Тем более подобная практика применяется и в некоторых других приложениях.


Если уж разговор зашел про локальный хостинг, то можно ещё столкнуться при авторизации с ошибкой: Protected from CSRF

Чтобы исправить её необходимо закомментировать 2 строки в файле: public/.htaccess

# php_value session.cookie_httponly 1
# php_value session.cookie_secure 1

И если есть, то это:

#  <IfModule mod_headers.c>
#    Header onsuccess edit Set-Cookie ^(.*) "$1; SameSite=Strict; HttpOnly; Secure"
#  </IfModule>

На реальном хостинге всё должно работать…


English:

Using a /public folder is a white-list approach to security, meaning everything is banned except for the things that are white listed (everything in the public folder).

Not using a /public folder is a black-list approach to security, meaning everything is allowed except for things that are black listed (rules defined in your webserver configuration file).

LibArea uses a white-list approach to web security. This is because we don't think it's a good idea to keep all of our system code in the root folder.

The situation is similar with Content Security Policy.

Evg Evg + 5.5k

7 Ответов

  1. Хорошая идея написать статью, а то вижу много вопросов задают?

  1. Evg Evg 3 Апреля 2022

    Да. Когда 1 спрашивает, — это одно, но когда достаточно много людей интересуются, статья просто необходима.

  1. 4xpro 4xpro 4 Апреля 2022 (ред.)

    Основной недостаток index.php в подкаталоге (на мой взгляд, кстати, более понятным является имя www, а не public) — сложность поставить два таких приложения на одном домене на shared-хостинге без доступа к конфигу Apache (и знания, как его править). Ну и плюс установка становится неинтуитивной — нужно прочитать документацию, чтобы выяснить, куда должен указывать DocumentRoot. Кстати, не на всех хостингах его можно менять самому, иногда приходится писать в техподдержку (это для меня существенный минус).

    Я в своём движке сделал чуть иначе — в корень проекта положил .htaccess, в котором прописал

    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteRule ^(www/.*)$ $1 [QSA,L]  # защита от зацикливания
      RewriteRule ^(.*)$ www/$1 [QSA]
    </IfModule>

    В результате чего DocumentRoot можно направлять как в каталог www, так и на корень проекта, и всё будет работать и в том, и в другом случае, а каталоги вне www остаются недоступными.

    P.S. session.cookie_httponly прекрасно работают и на localhost, комментировать нужно только вторую строчку, т.к. она делает cookies доступными только по https.

  1. Evg Evg 4 Апреля 2022

    Спасибо большое, тут есть такая возможность, но менять (по умолчанию) не думаю, что стоит. Этот вопрос в частном порядке можно решить без особых проблем для VPS (что касается хостинга, не особо знаком с ним).

    Использование .htaccess я не рекомендую, т.к. идет в разрез с политикой безопасности, подхода, который используется тут (см. выше: белый и черный список).

  1. Murad Murad 26 Июля 2022 (ред.)

    Сегодня решил поставить, что-то у меня не запускается. Раньше работало через .htaccess, решил использовать настройки веб-сервера.
    Вроде ничего сложного, но получаю ошибку error 500. Базу прописал, на папку storage необходимые права стоят, три часа тупо не пойму в чём дело))
    Обработчик PHP 8.0.12 (alt) CGI База данных mysql-8.0.28
    Изначальная конфигурация моего сервера Apache 2.4

    <VirtualHost 127.0.0.1:8080>
        ServerName example.ru
        DocumentRoot /var/www/www-root/data/www/example.ru
        ServerAdmin webmaster@example.ru
        AddDefaultCharset off
        AssignUserID www-root www-root
        CustomLog /var/www/httpd-logs/example.ru.access.log combined
        ErrorLog /var/www/httpd-logs/example.ru.error.log
        <FilesMatch "\.ph(p[3-5]?|tml)$">
            SetHandler application/x-httpd-php5
        </FilesMatch>
        ScriptAlias /php-bin/ /var/www/php-bin-isp-php80/www-root/example.ru/
        AddHandler application/x-httpd-php5 .php .php3 .php4 .php5 .phtml
        Action application/x-httpd-php5 /php-bin/php
        SetEnvIf X-Forwarded-Proto https HTTPS=on
        ServerAlias www.example.ru
        DirectoryIndex index.php index.html
    </VirtualHost>
    <Directory /var/www/www-root/data/www/example.ru>
        Options +Includes -ExecCGI
    </Directory>
  1. Evg Evg 26 Июля 2022

    А выйдите на меня в чате. Попробую помочь.

  1. Murad Murad 26 Июля 2022

    Дискорт установлю напишу, что в телефоне нет, что в компьютере, всё обновил, а нужые приложения не все установлены.