Identification

Sécurité Apache 2 : Le B.A.-BA


Premier billet d'une petite série concernant le serveur Web Apache 2 et l'auto-hébergement dans un environnement LAMP. Le propos n'est pas ici de proposer LA solution ultime de sécurisation, mais de lister un ensemble de bon réflexes ; l'idée de fond étant de compliquer un minimum la tâche à une personne mal intentionnée.

L'environnement cible est un serveur apache 2.2.x.

Limiter les ressources allouées

Limiter le nombre de clients pouvant se connecter à votre serveur Web, ou les ressources que vous souhaitez lui attribuer sont généralement de bonnes idées. Cela permet de contrôler la charge du serveur et limite la portée de certaines attaques par déni de service.

La configuration générale d'Apache 2 se trouve dans le fichier apache2.conf généralement présent dans le répertoire /etc/apache2/.

Avant d'éditer ce fichier il faut se renseigner sur le nom du modules multi-processus qui tourne sur le serveur. Ceci permet de déterminer la section du fichier de configuration qu'il faudra paramétrer. Il existe 3 modules multi-processus (MPM) pour Apache : prefork (mpm_prefork_module), worker (mpm_worker_module), et event (mpm_event_module).

Pour connaitre le module qui est activé sur le serveur, il suffit d'utiliser la commande apachectl comme suit :

# apachectl -M | grep mpm
 mpm_prefork_module (static)
Syntax OK

Nous voyons ici que c'est le module mpm_prefork_module qui est actif. La configuration de nos directive se fera donc essentiellement dans la section suivante du fichier de configuration (à adapter selon votre cas) :

#...
<IfModule mpm_prefork_module>
    #...
</IfModule>
#...

Note concernant apache v2.4 : la configuration de ce module se trouve désormais dans le fichier : /etc/apache2/mods-available/mpm_prefork.conf.

Vous pouvez maintenant éditer le fichier via nano ou l'éditeur de votre choix. Si vous êtes néophyte, nano est plus facile à prendre en main :

# nano /etc/apache2/apache2.conf

Dans ce fichier, les directives qui nous intéressent plus particulièrement sont les suivantes (c.f. documentation des directives communes aux modules mpm et documentation du module prefork) :

KeepAlive
Détermine si les connexions doivent être de type persistantes ou non persistantes. Régler sur "On" pour des connexions persistantes. Ce paramètre agit sur la performance du serveur (les connexions persistantes sont plus performantes).
MaxKeepAliveRequests
Nombre maximal de requêtes au cours d'une connexion persistante. Régler sur "0" pour illimité (déconseillé).
KeepAliveTimeout
Temp maximum durant lequel une connexion inactive doit être maintenue, au delà la connexion est fermée.
StartServers
Nombre de processus serveur enfant créés au démarrage d'Apache.Ce nombre  est modifié dynamiquement en fonction de la charge, par conséquent il est généralement inutile de changer sa valeur.
MinSpareServers
Nombre minimum de processus serveurs enfants inactifs. S'il y a moins de MinSpareServers processus inactifs, le processus parent va créer de nouveaux enfants de la manière suivante : il en crée un, attend une seconde, il en crée deux, attend une seconde, il en crée quatre, puis continue ainsi exponentiellement jusqu'à ce que son taux de création de processus enfants soit de 32 par seconde. Il ne s'arrête que lorsque le nombre de processus enfants correspond à la définition de la directive MinSpareServers.
La modification de ce paramètre ne peut s'avérer nécessaire que dans le cas de sites très sollicités. Définir ce paramètre à une valeur très grande est dans la plupart des cas une mauvaise idée.
MaxSpareServers
Nombre maximum de processus serveurs enfants inactifs. Permet de définir le nombre maximum souhaité de processus serveurs enfants inactifs. S'il y a plus de MaxSpareServers processus inactifs, le processus parent arrêtera les processus excédentaires. La modification de ce paramètre ne peut s'avérer nécessaire que dans le cas de sites très sollicités. Définir ce paramètre à une valeur très grande est cependant dans la plupart des cas une mauvaise idée.
MaxRequestsPerChild
Limite le nombre de demandes qu'un processus enfant peut gérer. Au delà de cette limite, le processus meurt. Si cette directive est fixée à "0", le processus ne meurt jamais.
MaxClients
Nombre de clients servis simultanément. Toute tentative de connexion au delà de ce nombre sera mise en file d'attente, jusqu'au nombre maximum contrôlé par la directive ListenBacklog.
ListenBackLog
Longueur maximale de la liste d'attente des connexions. Certains systèmes d'exploitation gèrent ce paramètre eux même ; il s'agit souvent d'un petit nombre, ce que je trouve personnellement préférable.

Comme très souvent : il n'y a pas de recette miracle ; et les valeurs de ces directives sont évidement à configurer en fonction de l'objet de votre serveur. Pour trouver les réglages optimaux dans votre cas d'utilisation, il n'y a qu'une chose à faire : tester différentes configurations.

Toutefois vous devrez tenir compte des données suivantes :

  • Le débit réseau maximal dont peut disposer votre serveur, ou que vous souhaitez lui accorder (en particulier le débit montant),
  • La capacité de traitement de votre machine (puissance, mémoire...),
  • Le type et le nombre de sites hébergés sur la même machine,
  • La fréquentation habituelle de votre serveur Web, si vous la connaissez.

Gardez à l'esprit (j'insiste) qu'il est inutile de sur-dimensionner un serveur Web alors qu'il est peu fréquenté et/ou que la machine qui l'héberge ne peut pas assumer la charge en terme de débit réseau ou de performances.

Pour vous donner quelques idées, voici un exemple de configuration qui pourrait être utilisé pour un très petit site (pages ou blog perso), auto-hébergé sur une très petite machine, à travers une connexion ADSL de 2 méga :

#...
KeepAlive On
#...
MaxKeepAliveRequests 30
#...
KeepAliveTimeout 5
#...
<IfModule mpm_prefork_module>
    MinSpareServers       1
    MaxSpareServers       5
    ListenBackLog        25
    StartServers          2
    MaxClients           10
    MaxRequestsPerChild   0
</IfModule>

Et une configuration qui pourrait être utilisée pour un petit site vitrine, hébergé sur une machine standard, à travers une connexion 100Mb/s :

#...
KeepAlive On
#...
MaxKeepAliveRequests 100
#...
KeepAliveTimeout 5
#...
<IfModule mpm_prefork_module>
    MinSpareServers       5
    MaxSpareServers      10
    ListenBackLog       200
    StartServers          5
    MaxClients          150
    MaxRequestsPerChild   0
</IfModule>

Une fois les modifications effectuées il faut demander à Apache d'avoir l'amabilité de les prendre en compte :

# /etc/init.d/apache2 reload

Masquer la version d'Apache

Le deuxième point important et d'éviter de mettre à disposition de l'utilisateur des informations qui pourraient êtres compromettantes. En effet par défaut Apache est un serveur bavard ; une simple requête telnet comme celle qui suit fournie souvent des informations essentielles concernant la configuration du serveur :

telnet localhost 80
Trying ::1...
Connected to localhost.localdomain.
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.1 400 Bad Request
Date: Sat, 22 Jun 2013 14:38:43 GMT
Server: Apache/2.2.22 (Debian)
Vary: Accept-Encoding
Content-Length: 313
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.2.22 (Debian) Server at localhost.localdomain Port 80</address>
</body></html>
Connection closed by foreign host.

Nous pouvons voir ici que le serveur Apache interrogé tourne sur un système Debian, donc très probablement un Debian GNU/Linux qui est plus utilisé que les versions Hurd, ou BSD. Nous découvrons également qu'Apache est ici en version 2.2.22.

Ces informations, qui semblent anodines, sont inutilement exposées aux yeux des curieux et pourraient déjà être suffisante pour tenter d'exploiter une faille de sécurité. Afin d'empêcher apache d'afficher ces informations, qui ne servent à rien et pourraient simplifier la tâche d'une personne mal intentionnée, il suffit d'éditer le fichier /etc/apache2/conf.d/security et d'y modifier les directives ServerTokens et ServerSignature :

# nano /etc/apache2/conf.d/security
#...
ServerTokens Prod
#...
ServerSignature Off
#...

Une fois la modification terminée il faut forcer le rechargement des fichiers de configurations d'Apache :

# /etc/init.d/apache2 reload

Notez que si vous désirez vous tenir informé sur les failles de sécurités d'Apache, ce que je vous invite à faire, vous pouvez vous rendre sur le site officiel, section Security Reports.

Masquer la version de PHP

Si vous utilisez PHP sur votre serveur Apache, je vous conseille également de veiller à ce que la directive expose_php du fichier php.ini soit désactivée. Ceci permet d'éviter que la version de PHP ne soit disponible dans les entêtes de la réponse HTTP du serveur :

# nano /etc/php5/apache2/php.ini
;...
expose_php = Off
;...

Sécuriser phpMyAdmin

Vous utilisez phpMyAdmin ? Un petit tour par ici s'impose.