Accueil
Trucs & Astuces
Scripts
Regex
Annuaire
Articles
.
|
Articles PHP 4.1.0 et les variables globales Par J-Pierre DEZELUS
Décembre 2001
» Une configuration standard aujourd'hui » Le trou de sécurité » Une configuration conseillée demain » La transition
Aujourd'hui, dans une configuration standard de PHP, vous récupérez le contenu des cookies, des données saisies dans un formulaire ou des paramètres passés sur l'URL (query string) directement en manipulant les variables associées par leur nom.
Par exemple, si vous avez laissé sur le client un cookie nommé monCookie grâce à l'instruction SetCookie('monCookie', 'valeur'), vous récupérerez automatiquement son contenu dans la variable $monCookie lors d'accès ultérieurs du client à vos scripts.
Pour un champ de formulaire (validé avec la méthode POST) <INPUT NAME='monChamp'> vous pourrez manipuler la variable $monChamp, et pour une URL http://www.monsite.com/?monParam=5 vous accéderez à la variable $monParam.
Ce mécanisme simple est rendu possible grâce au paramètre register_globals du fichier php.ini.
Jusqu'à aujourd'hui ce paramètre est positionné à On par défaut (même avec la version PHP 4.1.0), ce qui permet de manipuler directement les variables globales de type ENV/GET/POST/COOKIE/SERVER (EGPCS) en utilisant le principe décrit précédemment.
De plus si vous avez positionné le paramètre track_vars du fichier php.ini à On (valeur par défaut depuis PHP 4.0.3), vous récupérez automatiquement les variables d'environnement, les variables serveur, et les variables GET/POST/Cookie dans les tableaux associatifs $HTTP_ENV_VARS, $HTTP_SERVER_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS, et $HTTP_COOKIE_VARS.
Si nous reprenons les exemples précédents, avec ce type de configuration nos données sont donc aussi accessibles via les variables $HTTP_COOKIE_VARS['monCookie'], $HTTP_POST_VARS['monChamp'] et $HTTP_GET_VARS['monParam'].
Voici la liste des variables prédéfinies :
- $HTTP_COOKIE_VARS : ensemble des cookies.
- $HTTP_GET_VARS : variables passées au script par la méthode GET (formulaire en GET, ou via l'URL).
- $HTTP_POST_VARS : variables passées au script via un formulaire validé avec la méthode POST.
- $HTTP_ENV_VARS : variables de l'environnement d'exécution de PHP. Exemples : HOME, PATH, ...
- $HTTP_SERVER_VARS : variables fournies par le serveur HTTP. Exemples : SERVER_NAME, REQUEST_METHOD, QUERY_STRING ... Dans le cas d'un serveur Apache, elles sont analogues aux variables d'environnement décrites ci-dessus.
- $HTTP_SESSION_VARS : variables de session (PHP4 uniquement).
Bien qu'il facilite grandement le travail des développeurs, le mécanisme de déclaration automatique des variables globales n'en reste pas moins un trou de sécurité évident.
Essayons de voir pourquoi sur un exemple un peu irréaliste je l'admets mais qui montre bien le problème.
Supposons un script index.php qui affiche des informations confidentielles à un utilisateur qui s'est préalablement identifié via un formulaire (login/password).
index.php
<?php include('verif-user.php'); // vérifie les saisies include('affiche-info.php'); // affiche les infos ?>
|
|
verif-user.php
<?php $authentifie = ($HTTP_POST_VARS['user'] == $user_admin && $HTTP_POST_VARS['pass'] == $pass_admin); ?>
|
|
affiche-info.php
<?php if ($authentifie) { echo "Il te reste 1 000 000 € sur ton compte !"; } ?>
|
|
Le premier script verif-user.php vérifie les données saisies par l'utilisateur et positionne la variable $authentifie à true si l'utilisateur est reconnu. Le second script affiche-info.php vérifie la valeur de cette variable et affiche les données confidentielles si l'authentification a réussi.
Avec la déclaration automatique des variables globales, et la connaissance des scripts sources il devient très simple d'accéder aux données confidentielles sans aucune authentification en appelant l'url htpp://www.lesite.com/affiche-info.php?authentifie=1.
Une variable $authentifie est créée et positionnée à true (1).
L'exemple est grossier, car nous pourrions placer les fichiers inclus dans un répertoire protégé (par un fichier .htaccess sous Apache par exemple) et surtout améliorer le script. Mais il montre bien le type de faille pouvant être utilisé sur un script pour récupérer des données privées.
Quoiqu'il en soit c'est ce type de trou de sécurité qu'il est très facile aujourd'hui d'exploiter quand on connait le contenu des scripts PHP, ce qui est le cas des nombreux projets GPL disponibles et utilisés sur le net.
Pour mettre fin à tout cela, le projet PHP a décidé de modifier à partir de la version 4.1.0 le principe de fonctionnement des variables globales.
A terme les paramètres register_globals et track_vars doivent disparaître du fichier php.ini, ce qui revient à dire qu'ils prendront tous les deux la valeur Off.
Il ne sera donc plus question d'utiliser directement les variables globales $monCookie, $monParam ou $monChamp. Mais plutôt les tableaux associatifs correspondants.
Pour faciliter la transition PHP 4.1.0 propose 3 nouvelles fonctionnalités :
- ces tableaux associatifs sont "créés" par défaut dans vos scripts sans qu'il soit nécessaire de mettre track_vars à On,
- ils sont accessibles à l'intérieur des fonctions sans qu'il soit nécessaire de les déclarer avec l'instruction global,
<?php function maFonction() { // 'global $_GET;' n'est plus nécessaire en début de fonction
echo $_GET['monParam']; } ?>
|
|
- ils changent de nom, pour devenir plus courts et plus simples. Désormais vous pourrez manipuler les tableaux $_GET, $_POST, $_COOKIE, $_SERVER et $_ENV. Les tableaux $HTTP_*_VARS correspondants sont amenés eux à disparaître.
L'objectif affiché par le PHP Group est que chaque administrateur de site positionne rapidement la variable register_globals à Off, et que chaque développeur PHP s'astreigne à manipuler les variables $_*.
Si nous reprenons notre exemple du début, nous accéderons donc désormais aux variables : $_COOKIE['monCookie'], $_POST['monChamp'] et $_GET['monParam']. Mais rien ne nous empêche dans nos scripts de manipuler ensuite des noms de variables plus simples :
<?php $monCookie = $_COOKIE['monCookie']; $monChamp = $_POST['monChamp']; $monParam = $_GET['monParam']; ?>
|
|
A noter qu'un autre tableau associatif est créé automatiquement, $_REQUEST, qui contient les variables de type GET, POST et COOKIE.
Ce tableau a les mêmes propriétés que les autres tableaux $_*.
Par ailleurs une fonction import_request_variables() a été introduite qui permet de récupérer simplement dans des variables globales le contenu des variables de type GET/POST/Cookie.
<?php import_request_variables("GC", "mesvars_"); ?>
|
|
Ce code va créer les variables globales $mesvars_monParam (type G=GET) et $mesvars_monCookie (type C=Cookie), mais pas $mesvars_monChamp, puisque que le caractère 'P' (POST) n'a pas été spécifié dans le 1er paramètre de la fonction.
Pour les variables de session, l'ajout d'une entrée au tableau associatif $_SESSION revient à créer une nouvelle variable de session, comme vous pouvez le faire aujourd'hui avec la fonction session_register().
Attention ce principe ne s'applique pas aux autres variables $_*. Ajouter une entrée à $_ENV n'est pas équivalent à l'appel de la fonction putenv().
Pour l'instant PHP 4.1.0 s'installe toujours avec le paramètre register_globals positionné à On par défaut, et les variables $HTTP_*_VARS restent accessibles dans vos scripts.
Mais je le rappelle, l'objectif du PHP Group est clair : faire disparaître (ou ignorer) à terme le paramètre register_globals, et les variables $HTTP_*_VARS.
C'est pourquoi dès aujourd'hui sur votre machine de test obligez-vous à mettre le paramètre register_globals à Off. Et si vous utilisez une version PHP < 4.1.0, manipulez les variables $HTTP_*_VARS, sinon travaillez avec les variables $_*.
Une solution un peu plus lourde, mais qui a l'avantage de fonctionner quelque soit la version de PHP, consiste à vérifier l'existence des tableaux $_* afin de privilégier leur utilisation. A défaut, ce seront les tableaux $HTTP_*_VARS qui seront exploités.
C'est ce qui est fait aujourd'hui par le projet phpMyAdmin au sein du fichier libraries/grab_globals.lib.php3.
Si vos scripts "tournent" dans une configuration avec register_globals à Off, ils tourneront dans une configuration avec register_globals à On.
Le contraire sera rarement vrai, et vous risquez de rencontrer de nombreux problèmes si votre hébergeur ou votre administrateur système décident de changer la version de PHP entrainant un register_globals à Off, ou si vous diffusez vos scripts sur le web et qu'ils sont exécutés dans une configuration qui n'est pas la vôtre.
Aujourd'hui quand vous effectuez une nouvelle installation de PHP sur une machine, vous faites généralement une copie du fichier php.ini-dist pour produire le fichier php.ini et garantir un fonctionnement normal de vos scripts.
A l'avenir il serait préférable de lui préférer le fichier php.ini-recommended qui contient des valeurs différentes pour plusieurs paramètres afin de garantir sécurité et performance à vos scripts. Il nécessitera par contre une réécriture partielle de certains éléments de votre code.
Voici quelques-uns des paramètres et leurs valeurs associées qu'il vous faudra un jour trouver dans votre fichier php.ini :
- register_globals = Off [sécurité, performance]
Nous en avons largement discuté de ce paramètre précédemment. Dans les prochaines versions de PHP il sera de toute façon mis à Off par défaut (c'est à dire aussi dans le fichier php.ini-dist).
- display_errors = Off [sécurité]
Les erreurs survenant pendant l'exécution de vos scripts ne provoquent plus de message à l'écran, pouvant révéler par exemple l'emplacement de vos fichiers inclus. Laisser à On sur la machine de développement, mais à Off sur celle en production.
- log_errors = On [sécurité]
En complément du paramètre display_errors, ce paramètre vous permettra de récupérer les messages d'erreurs dans vos fichiers de log pour analyse, puisqu'ils ne sont plus visualisables à l'écran.
- register_argc_argv = Off [performance]
Désactives la déclaration automatique des variables gloables $argv et $argc (paramètres passés en ligne de commande, en mode CGI ou exécutable).
- magic_quotes_gpc = Off [performance]
Les données de type GET/POST/COOKIE ne sont plus backslashées. Leur insertion dans une base de données devra se faire avec la fonction addslashes(). Voir l'article sur les Magic Quotes sur ce même site. Attention à ce paramètre dont la modification peut vous obliger à modifier la totalité de vos scripts ...
- variables_order = "GPCS" [performance]
Les variables d'environnement ne sont plus disponibles dans le tableau $HTTP_ENV_VARS[]. Il faut utiliser la fonction getenv() pour y accéder.
- error_reporting = E_ALL [code plus propre, sécurité(?)]
Toutes les erreurs de scripts sont signalées, dont celles pouvant survenir lorsqu'une variable est utilisée sans être préalablement initialisée ($mavar = 'valeur';).
|
|