Как безопасно размещать несколько сайтов с помощью Nginx и Php-fpm в Ubuntu 14.04

Вступление

Хорошо известно, что стек LEMP (Linux, nginx, MySQL, PHP) обеспечивает непревзойденную скорость и надежность для работы сайтов PHP. Другие преимущества этого популярного стека, такие как безопасность и изоляция, менее популярны.

В этой статье мы покажем вам преимущества безопасности и изоляции при работе сайтов на LEMP с разными пользователями Linux. Это будет сделано путем создания разных пулов php-fpm для каждого блока сервера nginx (сайта или виртуального хоста).

Предпосылки

Это руководство было протестировано на Ubuntu 14.04. Описанные установка и конфигурация будут аналогичны для других версий ОС или ОС, но команды и расположение файлов конфигурации могут отличаться.

Он также предполагает, что у вас уже установлены nginx и php-fpm. Если нет, выполните первый и третий шаг из статьи https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-on-ubuntu-14. -04 [Как установить стек Linux, nginx, MySQL, PHP (LEMP) в Ubuntu 14.04].

Все команды в этом руководстве должны выполняться от имени пользователя без полномочий root. Если для этой команды требуется root-доступ, ему будет предшествовать + sudo +. Если это еще не сделано, следуйте этому руководству: Initial Настройка сервера с Ubuntu 14.04 ,

Вам также понадобится полное доменное имя (fqdn), которое указывает на дроплет для тестирования в дополнение к стандартному + localhost +. Если у вас его нет под рукой, вы можете использовать + site1.example.org +. Отредактируйте файл + / etc / hosts + в вашем любимом редакторе, например, + sudo vim / etc / hosts + и добавьте эту строку (замените + site1.example.org + на fqdn, если вы его используете):

/ и т.д. / хосты

...
127.0.0.1 site1.example.org
...

Причины, чтобы обеспечить LEMP дополнительно

При обычной настройке LEMP существует только один пул php-fpm, который запускает все сценарии PHP для всех сайтов под одним и тем же пользователем. Это создает две основные проблемы:

  • Если веб-приложение на одном сервере nginx блокируется, т.е. Субдомен или отдельный сайт, будет взломан, все сайты в этой Droplet также будут затронуты. Злоумышленник может прочитать файлы конфигурации, включая сведения о базе данных, других сайтов или даже изменить их файлы.

  • Если вы хотите предоставить пользователю доступ к сайту в Droplet, вы фактически предоставите ему доступ ко всем сайтам. Например, вашему разработчику необходимо работать в промежуточной среде. Однако даже с очень строгими правами доступа к файлам вы по-прежнему будете предоставлять ему доступ ко всем сайтам, включая ваш основной сайт, в одной и той же Droplet.

Вышеуказанные проблемы решаются в php-fpm путем создания другого пула, который запускается под разными пользователями для каждого сайта.

[[step-1-- configuring-php-fpm]] === Шаг 1 - Настройка php-fpm

Если вы выполнили предварительные условия, у вас уже должен быть один функциональный веб-сайт в Droplet. Если вы не указали для него пользовательский fqdn, вы сможете получить к нему доступ через fqdn + localhost + локально или по IP-адресу капли удаленно.

Теперь мы создадим второй сайт (site1.example.org) с собственным пулом php-fpm и пользователем Linux.

Начнем с создания нужного пользователя. Для лучшей изоляции новый пользователь должен иметь свою собственную группу. Итак, сначала создайте группу пользователей + site1 +:

sudo groupadd site1

Затем, пожалуйста, создайте пользователя site1, принадлежащего этой группе:

sudo useradd -g site1 site1

Пока новый пользователь site1 не имеет пароля и не может войти в Droplet. Если вам нужно предоставить кому-то прямой доступ к файлам этого сайта, то вы должны создать пароль для этого пользователя с помощью команды + sudo passwd site1 +. С новой комбинацией пользователь / пароль пользователь может удаленно войти в систему с помощью ssh или sftp. Для получения дополнительной информации и сведений о безопасности проверьте статью https://www.digitalocean.com/community/questions/setup-a-secondary-ssh-sftp-user-with-limited-directory-access[Setup вторичного пользователя SSH / SFTP с ограниченным доступом к каталогу.

Затем создайте новый пул php-fpm для site1. По своей сути пул php-fpm - это просто обычный процесс Linux, который выполняется под определенным пользователем / группой и прослушивает сокет Linux. Он также может прослушивать комбинацию IP: порт, но для этого потребуется больше ресурсов Droplet, и этот метод не является предпочтительным.

По умолчанию в Ubuntu 14.04 каждый пул php-fpm должен быть настроен в файле внутри каталога + / etc / php5 / fpm / pool.d +. Каждый файл с расширениями + .conf + в этом каталоге автоматически загружается в глобальную конфигурацию php-fpm.

Итак, для нашего нового сайта давайте создадим новый файл + / etc / php5 / fpm / pool.d / site1.conf +. Вы можете сделать это с вашим любимым редактором, как это:

sudo vim /etc/php5/fpm/pool.d/site1.conf

Этот файл должен содержать:

/etc/php5/fpm/pool.d/site1.conf

[site1]







pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
chdir = /

В приведенной выше конфигурации обратите внимание на эти конкретные параметры:

  • + [site1] + - имя пула. Для каждого пула вы должны указать уникальное имя.

  • + user и` + group` означают пользователя Linux и группу, в которой будет работать новый пул.

  • + listen + должен указывать на уникальное местоположение для каждого пула.

  • + listen.owner + и + listen.group + определяют владельца прослушивателя, т.е. сокет нового пула php-fpm. Nginx должен уметь читать этот сокет. Вот почему сокет создается с пользователем и группой, в которой работает nginx - + www-data +.

  • + php_admin_value + позволяет вам установить пользовательские значения конфигурации php. Мы использовали его для отключения функций, которые могут запускать команды Linux - + exec, passthru, shell_exec, system +.

  • + php_admin_flag + похож на + php_admin_value +, но это просто переключатель для логических значений, т.е. включить и выключить. Мы отключим PHP-функцию + allow_url_fopen +, которая позволяет PHP-скрипту открывать удаленные файлы и может использоваться злоумышленником.

Параметры + pm + находятся за пределами текущей темы безопасности, но вы должны знать, что они позволяют вам настроить производительность пула.

Опция + chdir + должна быть + / +, которая является корнем файловой системы. Это не должно быть изменено, если вы не используете другую важную опцию + chroot +.

Опция + chroot + специально не включена в вышеуказанную конфигурацию. Это позволило бы вам запускать пул в тюрьме, то есть заблокирован внутри каталога. Это очень важно для безопасности, потому что вы можете заблокировать пул внутри корня сайта. Однако эта максимальная безопасность вызовет серьезные проблемы для любого приличного приложения PHP, которое использует системные двоичные файлы и приложения, такие как Imagemagick, которые не будут доступны. Если вас больше интересует эта тема, пожалуйста, прочитайте статью https://www.digitalocean.com/community/tutorials/how-to-use-firejail-to-set-up-a-wordpress-installation-in-a- jailed-environment [Как использовать Firejail для установки WordPress в защищенной среде].

Как только вы закончите с вышеуказанной конфигурацией, перезапустите php-fpm, чтобы новые настройки вступили в силу с помощью команды:

sudo service php5-fpm restart

Убедитесь, что новый пул работает правильно, выполнив поиск его процессов следующим образом:

ps aux |grep site1

Если вы следовали точным инструкциям до этого момента, вы должны увидеть вывод, подобный следующему:

  14042  0.0  0.8 133620  4208 ?        S    14:45   0:00 php-fpm: pool site1
  14043  0.0  1.1 133760  5892 ?        S    14:45   0:00 php-fpm: pool site1

Красный - пользователь, под которым запускается процесс или пул php-fpm - site1.

Кроме того, мы отключим кэширование php по умолчанию, предоставляемое opcache. Это конкретное расширение для кэширования может быть полезно для производительности, но не для безопасности, как мы увидим позже. Чтобы отключить его, отредактируйте файл + / etc / php5 / fpm / conf.d / 05-opcache.ini + с привилегиями суперпользователя и добавьте строку:

/etc/php5/fpm/conf.d/05-opcache.ini

opcache.enable=0

Затем перезапустите php-fpm (+ sudo service php5-fpm restart +), чтобы настройки вступили в силу.

[[step-2-- configuring-nginx]] === Шаг 2 - Настройка nginx

После того, как мы настроили пул php-fpm для нашего сайта, мы настроим блок сервера в nginx. Для этого создайте новый файл + / etc / nginx / sites-available / site1 + с вашим любимым редактором, например так:

sudo vim /etc/nginx/sites-available/site1

Этот файл должен содержать:

/ И т.д. / Nginx / сайты Недоступные / site1

server {
   listen 80;


   index index.php index.html index.htm;



   location / {
       try_files $uri $uri/ =404;
   }

   location ~ \.php$ {
       try_files $uri =404;
       fastcgi_split_path_info ^(.+\.php)(/.+)$;

       fastcgi_index index.php;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       include fastcgi_params;
   }
}

Приведенный выше код показывает общую конфигурацию для блока сервера в nginx. Обратите внимание на интересные выделенные части:

  • Корень сети - это + / usr / share / nginx / sites / site1 +.

  • Имя сервера использует fqdn + site1.example.org +, который упоминается в предварительных условиях этой статьи.

  • + fastcgi_pass + определяет обработчик для файлов php. Для каждого сайта вы должны использовать разные сокеты Unix, такие как + / var / run / php5-fpm-site1.sock +.

Создайте корневой веб-каталог:

sudo mkdir /usr/share/nginx/sites
sudo mkdir /usr/share/nginx/sites/site1

Чтобы включить вышеуказанный сайт, вы должны создать символическую ссылку на него в каталоге + / etc / nginx / sites-enabled / +. Это можно сделать с помощью команды:

sudo ln -s /etc/nginx/sites-available/site1 /etc/nginx/sites-enabled/site1

Наконец, перезапустите nginx, чтобы изменения вступили в силу следующим образом:

sudo service nginx restart

[[step-3-- testing]] === Шаг 3 - Тестирование

Для запуска тестов мы будем использовать хорошо известную функцию phpinfo, которая предоставляет подробную информацию о среде php. Создайте новый файл с именем + info.php +, который содержит только строку + <? Php phpinfo (); ?> + `. Сначала вам понадобится этот файл на сайте nginx по умолчанию и его веб-корне `+ / usr / share / nginx / html / +. Для этого вы можете использовать такой редактор:

sudo vim /usr/share/nginx/html/info.php

После этого скопируйте файл в корневой каталог другого сайта (site1.example.org) следующим образом:

sudo cp /usr/share/nginx/html/info.php /usr/share/nginx/sites/site1/

Теперь вы готовы запустить самый простой тест для проверки пользователя сервера. Вы можете выполнить тест с помощью браузера или из терминала Droplet и lynx, браузера командной строки. Если у вас еще нет lynx в Droplet, установите его с помощью команды + sudo apt-get install lynx +.

Сначала проверьте файл + info.php + с вашего сайта по умолчанию. Он должен быть доступен под localhost следующим образом:

lynx --dump http://localhost/info.php |grep 'SERVER\["USER"\]'

В приведенной выше команде мы фильтруем вывод с помощью grep только для переменной + SERVER [" USER "] +, которая обозначает пользователя сервера. Для сайта по умолчанию вывод должен показывать пользователя по умолчанию + www-data следующим образом:

_SERVER["USER"]                 www-data

Аналогично, затем проверьте пользователя сервера на site1.example.org:

lynx --dump http://site1.example.org/info.php |grep 'SERVER\["USER"\]'

Вы должны увидеть это время в выходных данных пользователя + site1 +:

_SERVER["USER"]                 site1

Если вы установили какие-либо пользовательские настройки php для каждого пула php-fpm, то вы также можете проверить их соответствующие значения вышеуказанным способом, отфильтровав интересующий вас вывод.

Пока что мы знаем, что наши два сайта работают под разными пользователями, но теперь давайте посмотрим, как защитить соединение. Чтобы продемонстрировать проблему безопасности, которую мы решаем в этой статье, мы создадим файл с конфиденциальной информацией. Обычно такой файл содержит строку подключения к базе данных и содержит данные о пользователе и пароле пользователя базы данных. Если кто-то узнает эту информацию, он может сделать что-нибудь с соответствующим сайтом.

С вашим любимым редактором создайте новый файл на вашем главном сайте + / usr / share / nginx / html / config.php +. Этот файл должен содержать:

/usr/share/nginx/html/config.php

<?php
$pass = 'secret';
?>

В приведенном выше файле мы определяем переменную с именем + pass +, которая содержит значение + secret. Естественно, мы хотим ограничить доступ к этому файлу, поэтому мы установим его права доступа равными 400, что дает владельцу файла доступ только для чтения.

Чтобы изменить разрешения на 400, выполните команду:

sudo chmod 400 /usr/share/nginx/html/config.php

Кроме того, наш основной сайт работает под пользователем + www-data +, который должен иметь возможность прочитать этот файл. Таким образом, измените владельца файла на этого пользователя следующим образом:

sudo chown www-data:www-data /usr/share/nginx/html/config.php

В нашем примере мы будем использовать другой файл с именем + / usr / share / nginx / html / readfile.php +, чтобы прочитать секретную информацию и распечатать ее. Этот файл должен содержать следующий код:

/usr/share/nginx/html/readfile.php

<?php
include('/usr/share/nginx/html/config.php');
print($pass);
?>

Измените владельца этого файла на + www-data:

sudo chown www-data:www-data /usr/share/nginx/html/readfile.php

Чтобы подтвердить правильность всех прав и владельцев в веб-корне, выполните команду + ls -l / usr / share / nginx / html / +. Вы должны увидеть вывод, похожий на:

-r-------- 1 www-data www-data  27 Jun 19 05:35 config.php
-rw-r--r-- 1 www-data www-data  68 Jun 21 16:31 readfile.php

Теперь перейдите к последнему файлу на вашем сайте по умолчанию с помощью команды + lynx --dump http: // localhost / readfile.php +. Вы должны увидеть распечатанный вывод + secret +, который показывает, что файл с конфиденциальной информацией доступен на том же сайте, что является ожидаемым правильным поведением.

Теперь скопируйте файл + / usr / share / nginx / html / readfile.php + на второй сайт site1.example.org, например так:

sudo cp /usr/share/nginx/html/readfile.php /usr/share/nginx/sites/site1/

Чтобы поддерживать связь между сайтом и пользователем, убедитесь, что на каждом сайте файлы принадлежат соответствующему пользователю сайта. Сделайте это, изменив владельца вновь скопированного файла на site1 с помощью команды:

sudo chown site1:site1 /usr/share/nginx/sites/site1/readfile.php

Чтобы подтвердить, что вы установили правильные права доступа и владельца файла, перечислите содержимое веб-корня site1 с помощью команды + ls -l / usr / share / nginx / sites / site1 / +. Тебе следует увидеть:

-rw-r--r-- 1 site1 site1  80 Jun 21 16:44 readfile.php

Затем попробуйте получить доступ к тому же файлу с site1.example.com с помощью команды + lynx --dump http: // site1.example.org / readfile.php +. Вы увидите только возвращенное пустое пространство. Кроме того, если вы будете искать ошибки в журнале ошибок nginx с помощью команды grep + sudo grep error / var / log / nginx / error.log +, вы увидите:

2015/06/30 15:15:13 [error] 894#0: *242 FastCGI sent in stderr: "PHP message: PHP Warning:  include(/usr/share/nginx/html/config.php): failed to open stream: Permission denied in /usr/share/nginx/sites/site1/readfile.php on line 2

Предупреждение показывает, что сценарий с сайта site1.example.org не может прочитать конфиденциальный файл + config.php + с основного сайта. Таким образом, сайты, которые работают под разными пользователями, не могут поставить под угрозу безопасность друг друга.

Если вы вернетесь к концу этой части, посвященной настройке, вы увидите, что мы отключили кэширование по умолчанию, предоставляемое opcache. Если вам интересно, почему, попробуйте снова включить opcache, установив с привилегиями суперпользователя + opcache.enable = 1 + в файле + / etc / php5 / fpm / conf.d / 05-opcache.ini + и перезапустите php5-fpm с помощью команды + sudo service php5-fpm restart +.

Удивительно, но если вы снова запустите шаги тестирования в том же порядке, вы сможете прочитать конфиденциальный файл независимо от его владельца и разрешения. Об этой проблеме в opcache уже давно сообщалось, но на момент написания этой статьи она еще не была исправлена.

Заключение

С точки зрения безопасности важно использовать пулы php-fpm с разными пользователями для каждого сайта на одном веб-сервере Nginx. Даже если это приведет к небольшому снижению производительности, такая изоляция может предотвратить серьезные нарушения безопасности.

Идея, описанная в этой статье, не уникальна, и она присутствует в других подобных технологиях изоляции PHP, таких как SuPHP. Тем не менее, производительность всех других альтернатив намного хуже, чем у php-fpm.

Related