Protéger un serveur web Apache2 avec suEXEC et suPHP

25
nov.
2012
  • Google Plus
  • LinkedIn
  • Viadeo
Posted by: Yann C.  /   Category: Administration réseaux et systèmes / OS   /   7 commentaires

Sur la plupart des services d’hébergement mutualisés actuels, chaque site est indépendant des autres au niveau de l’utilisateur Apache. En effet, lors du déploiement basique d’un serveur web, l’utilisateur sous lequel fonctionne le démon est la plupart du temps « www-data », « nobody » ou « apache ». Cela signifie que si plusieurs sites existent sous la même instance d’Apache, tous utilisent le même utilisateur. Ainsi, si l’un des site s’avère corrompu par un utilisateur malveillant, et qu’un shell est obtenu, alors l’assaillant peut profiter pleinement de tous les droits de l’utilisateur sous lequel tourne le serveur web. Tous les sites s’avèrent donc vulnérables.

Une des techniques la plus répandue est de scinder chaque site d’un hébergement mutualisé via des utilisateurs (Unix) distincts. Cette méthode permet de cloisonner l’exécution des scripts web d’un site à un seul et unique utilisateur, empêchant ainsi que cet utilisateur puisse altérer les autres sites mutualisés.

Cette configuration est à réaliser en amont du déploiement des divers sites. Dans le cas d’une migration d’un environnement déjà en production, des manipulations supplémentaires peuvent être nécessaire (modification des .htaccess etc.).

Deux modules d’Apache permettent de réaliser une telle configuration aisément :

  • suEXEC : module permettant d’exécuter des scripts CGI à partir de l’utilisateur propriétaire du dit script.
  • suPHP : module permettant d’exécuter des scripts PHP à partir de l’utilisateur propriétaire.

Après l’installation et le déploiement de ces modules de sécurité, la configuration de PHP5 sur le serveur web exploitera le fichier de configuration php.ini CGI.

Dans un premier temps, installer les modules concernés :

root@ubuntu:/# apt-get install apache2-suexec
root@ubuntu:/# apt-get install apache2-suexec-custom
root@ubuntu:/# apt-get install libapache2-mod-suphp

Pour la configuration de ceux-ci, considérons que tous les sites clients vont se trouver dans « /var/www/<SITE>/ », et que chaque répertoire propre à un site disposera des répertoires « httpdocs » pour le contenu du site en lui même et « log » pour la journalisation.

Modification de « /etc/apache2/suexec/www-data ». On indique le répertoire racine de tous les site dans ce fichier, puis le répertoire contenant les fichiers de chaque site (httpdocs).

root@ubuntu:/var/www/monsite/httpdocs# cat /etc/apache2/suexec/www-data
/var/www
httpdocs
# The first two lines contain the suexec document root and the suexec userdir
# suffix. If one of them is disabled by prepending a # character, suexec will
# refuse the corresponding type of request.
# This config file is only used by the apache2-suexec-custom package. See the
# suexec man page included in the package for more details.

Pour la configuration de « suphp », il est nécessaire de connaitre l’uid et le gid minimum d’exécution des scripts web. Il est conseillé d’indiquer ceux de l’utilisateur par défaut « www-data » (33 ou 100 généralement) que l’on peut récupérer via la commande:

root@ubuntu:/# id www-data
uid=33(www-data) gid=33(www-data) groupes=33(www-data)

Configuration du fichier « /etc/suphp/suphp.conf » :

[root@[dedix chrooted]:/]$ cat /etc/suphp/suphp.conf
[global]
;Path to logfile
logfile=/var/log/suphp/suphp.log
 
;Loglevel
loglevel=info
 
;User Apache is running as
webserver_user=www-data
 
;Path all scripts have to be in
docroot=/var/www:${HOME}/httpdocs:/usr/share
 
;Path to chroot() to before executing script
;chroot=/mychroot
 
; Security options
allow_file_group_writeable=false
allow_file_others_writeable=false
allow_directory_group_writeable=false
allow_directory_others_writeable=false
 
;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=false
 
;Send minor error messages to browser
errors_to_browser=false
 
;PATH environment variable
env_path=/bin:/usr/bin
 
;Umask to set, specify in octal notation
umask=0022
 
; Minimum UID
min_uid=33
 
; Minimum GID
min_gid=33
 
[handlers]
;Handler for php-scripts
application/x-httpd-suphp='php:/usr/bin/php-cgi'
 
;Handler for CGI-scripts
x-suphp-cgi='execute:!self'

Ajouter les chemins d’accès aux scripts, notamment « /usr/share » s’il y a une installation de phpMyAdmin :

;Path all scripts have to be in
docroot=/var/www:${HOME}/httpdocs:/usr/share

Désactiver la vérification des racines des « vhost » :

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=false

Enfin, régler convenablement l’uid/gid minimum avec celui du compte « www-data »; ainsi que l’umask par défaut « 0022 ».

Pour laisser la main au module suPHP et suEXEC, la désactivation du module PHP5 est requise. suEXEC exploitera le fichier de configuration « /etc/php5/cgi/php.ini » à l’avenir :

root@ubuntu:/# a2dismod php5
root@ubuntu:/# a2enmod suexec
root@ubuntu:/# a2enmod suphp

Il ne reste plus qu’à déployer chacun des sites dans « /var/www ». Chaque site nécessite la création d’un nouvel utilisateur/groupe/home qui lui est propre ! Ainsi « /var/www/ » ne doit pas déjà contenir de répertoire pour un site.

root@ubuntu:/var/www# useradd --home /var/www/monsite/ --create-home monsite
root@ubuntu:/var/www# mkdir -p monsite/httpdocs
root@ubuntu:/var/www# mkdir -p monsite/log

A noter que vous pouvez ajouter un mot de passe pour chaque compte de site (utile pour avoir un serveur FTP par site qui pointe dans son $HOME respectif). Pour définir le mot de passe de chaque compte, utiliser la commande « passwd » ou automatiser la définition du mot de passe via l’attribut « -p » de la commande « useradd » (nécessite un hachage md5-unix, qui peut être créé via le paquet « makepasswd« ).

Créer un fichier de test dans « /var/www/monsite/httpdocs/index.php » contenant la vérification de l’utilisateur d’exécution courante :

<?php
system('/usr/bin/id');
echo '<br />';
system('/usr/bin/whoami');
echo '<br />';
phpinfo();
?>

Ne pas oublier que tous les fichiers/dossiers d’un site protégé par suEXEC et suPHP doivent être la propriété du seul utilisateur Unix autorisé à exploiter le site précédemment créé. Ainsi, redéfinir le chown :

root@ubuntu:/var/www# chown -R monsite:monsite monsite/

Pour finir, il faut indiquer à Apache2 que tel site doit fonctionner sous tel utilisateur. Pour cela, c’est dans les fichiers des « vhosts » qu’une nouvelle directive fait son apparition :

root@ubuntu:/etc/apache2/sites-available# cat monsite
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/monsite/httpdocs
ServerName www.monsite.fr
ServerAlias monsite.fr
SuexecUserGroup monsite monsite
<Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
ErrorLog /var/www/monsite/log/error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog /var/www/monsite/log/access.log combined
</VirtualHost>

Il est conseillé dans ce fichier « vhost » de rediriger la journalisation vers le répertoire « log » précédemment créé pour le site en question. Indiquer le nom du site, les bons alias, le répertoire racine et la directive suEXEC qui précise l’utilisateur et le groupe propriétaire du site :

SuexecUserGroup monsite monsite

Activation du nouveau site (vhost) :

root@ubuntu:/etc/apache2/sites-available# a2ensite monsite

Enfin, redémarrage d’Apache avec toute la nouvelle configuration des modules :

root@ubuntu:/# /etc/init.d/apache2 stop
Stopping web server: apache2.
root@ubuntu:/# /etc/init.d/apache2 start
Starting web server: apache2.

Vérification de la bonne configuration :

Vérification du fonctionnement de suEXEC et suPHP

Vérification du fonctionnement de suEXEC et suPHP

On constate que le script « index.php » créé tout à l’heure s’exécute bien. La commande « /usr/bin/id » retourne bien « monsite » ainsi que le « whoami » pour le compte d’exécution courant. La configuration de PHP5 est à présent gérée en mode CGI. Chaque site est à présent scindé par le biais de son utilisateur propriétaire défini dans son fichier vhost.

Dans le cas d’une erreur interne au serveur (erreur 500), vérifier le propriétaire des scripts vis-à-vis du compte défini dans le fichier vhost.

Ce mécanisme est très simple à mettre en oeuvre et permet d’apporter une sécurité notable à un environnement web complet. Couplé à un serveur FTP type « vsFTPd« , chaque site est administrable via FTP en connaissance du nom d’utilisateur/mot de passe propre à chaque site.

  • Google Plus
  • LinkedIn
  • Viadeo
Yann C.

About the Author : Yann C.

Consultant en sécurité informatique et s’exerçant dans ce domaine depuis le début des années 2000 en autodidacte par passion, plaisir et perspectives, il maintient le portail ASafety pour présenter des articles, des projets personnels, des recherches et développements, ainsi que des « advisory » de vulnérabilités décelées notamment au cours de pentest.