5.2. Configuration

PHP lit sa configuration depuis /etc/php5/apache2/php.ini. Par defaut, un certain nombre de paramètres sont plutôt dangereux et méritent d'être revus.

5.2.1. Restrictions

5.2.1.1. Couper PHP

La première et la plus radicale des restictions possibles est de désactiver l'interprétation des scripts PHP globalement sur le serveur avec la directive engine off. On pourra les autoriser ensuite dans les VirtualHosts par des directives spéciales comme décrit dans Section 5.2.4, « Exceptions ».

5.2.1.2. Masquer PHP

Même si ce n'est pas un moyen de protection valable, on peut toujours masquer la présence de PHP afin de rendre les choses plus difficiles pour les éventuels attaquants. PHP est plutôt verbeux sur sa présence. On trouve même dans les versions récentes, des URL easter-eggs [10]. On pourra les supprimer en mettant la variable expose_php [11] à Off. Cela ne suffit bien sûr pas : quand on a affaire à des fichiers se terminant par .php, cela lève le doute assez rapidement... Il faudra donc aussi modifier le handler PHP, définit dans /etc/apache2/mods-available/php5.conf pour y ajouter d'autres extensions moins « bavardes ». On pourra même demaner à Apache de renvoyer tous les fichiers .html au moteur PHP. C'est discret, mais le coût en performance peut être important si la proportion pages statiques/pages dynamiques est défavorable sur le serveur.

5.2.1.3. Limiter l'injection de code

Lorsque PHP est activé (globalement, ou sur un virtualhost), la dernière chose que nous voulons le voir faire est de charger du code à notre insu. Il est donc conseillé de mettre la valeur de enable_dl à Off. allow_url_fopen permet de charger du code PHP distant en ouvrant un URL (par include ou fopen). Il faudra aussi désactiver cette possibilité en mettant la directive à Off.

5.2.1.4. Variables globales

PHP a toujous été handicapé par la nécessité de maintenir une certaine compatibilité ascendante. Les variables register_globals, register_long_arrays et register_argc_argv font partie de cet héritage. Mais pour déployer des scripts « modernes » et surtout bien écrits, il n'est pas nécessaire (et même dangereux) d'activer ces paramètres. Il faudra donc tous les mettre à Off.

5.2.1.5. Supprimer des fonctions

PHP sait faire beaucoup. Parfois un peut trop dans le contexte de scripts web. Il est heureusement possible de desactiver certaines fonctions du language avec disable_functions. Il est probablement plus sûr de désactiver les fonctions suivantes : chgrp, chmod, chown, diskfreespace, dl, escapeshellcmd, exec, get_current_user, getmypid, getmyuid, getrusage, highlight_file, ignore_user_abord, ini_alter, ini_restore, ini_set, leak, link, listen, login, passthru, php_uname, popen, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, proc_get_status, proc_nice, proc_open, proc_terminate, set_time_limit, shell_exec, show_source, socket_bind, socket_listen, system et virtual. Attention toutefois : on ne peut configurer ce paramètre que dans php.ini, et non dans la configuration d'Apache (principale ou virtualhost). La valeur affectée sera donc globale.

5.2.1.6. Limiter l'accés au système de fichiers

Sur des serveurs ayant plusieurs virtualhosts, il est préférable de restreindre l'accès au filesystem aux secteurs strictement nécessaires. L'utilisateur alice qui met ses pages, par exemple, dans /home/alice/www/ n'a pas besoin d'ouvrir des fichiers se trouvant au dessus de son répertoire web dans le filesystem. Le paramètre open_basedir permet de configurer un répertoire au dessus duquel il ne sera pas possible d'ouvrir de fichier. Il conviendra de le spécifier dans chaque virtualhost.

doc_root permet de spécifier la racine des scripts php, à ne pas confondre avec open_basedir qui donne la racine de tous les fichiers accessibles par PHP (éventuellement des fichiers de données ou des fichiers de session).

5.2.1.7. Protection des sessions

Pour des raisons de sécurité, on veillera aussi à déplacer le répertoire utilisé pour stocker les fichiers de session (par défaut, /var/lib/php5/ sous Ubuntu). Il faudra créér un répertoire propre à chaque virtualhost, afin de limiter les éventuels problèmes de vol de session. On utilisera la variable session.save_path pour spécifier le nouveau répertoire et on veillera à mettre une valeur située sous celle d'open_basedir. Dans le cas contraire, PHP ne pourrait sauver les fichiers de session.

5.2.1.8. Upload de fichiers

Selon la destination du serveur, on pourra être tenté de positionner la variable file_uploads à off. Cela désactivera la possibilité d'envoyer des fichiers en POST vers des scripts PHP.

Si l'on désire conserver cette possibilité, il vaut mieux modifier la variable upload_tmp_dir et lui affecter un répertoire accessible depuis le virtualhost (donc sous le répertoire pointé par open_basedir).

5.2.1.9. safe_mode

Un paramètre regroupe à lui seul plusieurs restrictions améliorant la sécurité : safe_mode. Il permet notamment de faire respecter les droits associés aux fichiers (un fichier appartenant à X ne pourra être utilisé par un script appartenant à Y) et d'empécher la modification des variables d'environnement listées dans le paramètre safe_mode_protected_env_vars.

Le paramètre safe_mode désactive aussi certaintes fonctions, listées dans le manuel de PHP, donc la plupart sont déja couvertes par la valeur recommandée pour disable_functions. Il faudra donc mettre cette valeur à On sans hésiter.

5.2.2. Limites

PHP permet de fixer quelques limites pour l'exécution des scripts. Ces limites pemettent d'éviter d'avoir un serveur complètement surchargé par l'exécution d'un seul script. En revanche, il n'y a pas de provision possible sur le nombre de scripts exécutables en parallèle, qui potentiellement peut être égal au nombre de processus Apache. Il faut donc garder à l'esprit que ce n'est pas un mécanisme qui permet de se protéger contre les attaques, mais plutôt contre des erreurs de programmations.

memory_limit permet de limiter la mémoire maximum utilisable par un script PHP. Il est vivement recommandé de ne pas laisser la valeur pas défaut de 128M. Il est difficile d'estimer la bonne valeur pour un script, mais dans la plupart des cas, 10M devraient amplement suffire.

La durée d'exécution d'un script peut être fixée à l'aide de max_execution_time. Par défaut, sa valeur est 30 (secondes).

max_input_time permet de limiter la durée d'une requète client. Par défaut, il n'y a aucune valeur maximum. Des clients mal configurés pourraient donc mobiliser des scripts trop longtemps. En positionnant cette variable à une valeur différente de -1, on peut limiter ce temps. Il faut cependant noter que ce temps comprend la totalité de la requète cliente, y compris des fichiers « uploadés » en POST. Donc si le script recoit des fichiers importants (ou sert à faire des tests de bande passante par exemple), il faudra prévoir un valeur suffisamment grande pour les clients lents.

max_input_time est donc liée à la variable upload_max_filesize qui limite la taille maximale d'un fichier uploadé (2M par défaut).

De même, la taille maximum d'un envoi par POST, fixé dans post_max_size (8M par défaut), devra être supérieur à upload_max_filesize (pour couvrir l'envoi de fichier) et servira à calibrer la durée maximum de la requète client.

Pour clore la série des limitations, on pourra aussi en citer une qu'il est peut être souhaitable d'appliquer à la configuration Apache. Les scripts PHP incluent souvent des portions de code depuis d'autres fichiers, se terminant en général par .inc. Bien que rien n'oblige un développeur à nommer ces fichiers .inc, c'est une pratique assez courante[12]. Le problème avec cette pratique est qu'Apache, par défaut, n'a pas de handler (gestionnaire) associé aux extensions .inc. Un fichier avec une telle extension fichier sera donc affiché comme n'importe quel autre fichier texte, donnant des informations potentiellement sensibles [13]. On peut demander à Apache de ne pas servir ces fichiers : ils sont inclus directement depuis les scripts coté serveur; inutile donc d'offrir la possibilité aux clients HTTP de voir le contenu de ces fichiers. Il en va de même pour les fichiers avec les extensions ~, .bak, .swp, .old, .sav[e], etc... qui sont parfois envoyés en FTP en même temps que des fichiers légitimes ou laissés sur place par des développeurs éditant directement sur le serveur.

<Files ~ "\.(inc|bak|swp|old|sav[e]?|~)$">
 Order allow,deny
 Deny from all
</Files>

5.2.3. Gestion d'erreurs

PHP a un système de gestion d'erreurs qui lui permet de les afficher dans les pages HTML retournées ou de les envoyer vers un fichier spécifique. Il vaudra mieux utiliser cette dernière méthode pour les applications en production : cela permet de donner un minimum d'informations via la page Web tout en permettant aux développeurs de voir les messages d'erreurs. Si l'on désire masquer la présence de PHP c'est aussi une modification recommandée. log_errors à On permet d'envoyer les erreurs vers le fichier définit dans error_log. On désactivera ensuite les messages d'erreur avec display_errors et display_startup_errors à Off.

5.2.4. Exceptions

Dans le cas ou un paramètre doit avoir une valeur spéciale pour un VirutalHost particulier, il est possible d'affecter des valeurs aux variables de configuration PHP dans une section <VirtualHost ...> avec la directive php_admin_value. Par exemple, si le VirutalHost d'Alice doit pouvoir utiliser l'upload de fichiers et nécessite 50 Mb de mémoire pour son exécution, on pourra corriger la valeur de file_uploads et memory_limit uniquement pour lui :

root@ubuntu:~# cat /etc/apache2/sites-available/site_alice
<VirtualHost *>
  ServerAdmin alice@exemple.org
  ServerName alice.exemple.org
  DocumentRoot /home/alice/monsiteouebe/

  php_admin_flag engine on
  php_admin_flag file_uploads on
  php_admin_value memory_limit 50M
  ...

On privilégiera systématiquement php_admin_value au lieu de php_value pour changer les valeurs de configuration de PHP dans la configuration Apache. Cette dernière directive autorise le changement des valeurs dans un fichier .htaccess tandis que php_admin_value la fixe sans aucune possibilité de modification.

Seules les valeurs expose_php, disable_functions et disable_classes ne peuvent pas être modifiées dans la configuration d'Apache (voir http://fr.php.net/manual/fr/ini.php).



[10] Par exemple celui-ci donnant affichant les différents crédits concernant le développement de PHP.

[11] cette variable n'est utilisable que dans php.ini.

[12] Cette pratique pourrait être avantageusement remplacée par une autre consistant à nommer ces fichiers en .php et à les placer dans un sous répertoire /include par exemple.

[13] On pourra s'en convaincre en visitant, par exemple, cette adresse http://www.google.com/search?q=filetype%3Ainc+inurl%3Aconfig+%22dbname%22