Les tableaux superglobaux (dits aussi auto-globaux)
sont une nouveauté de PHP 4.2.0, les versions antérieures n'en possèdent pas.
De façon générale, une variable superglobale est automatiquement
disponible dans tous les environnements d'exécution.
Elle a donc une portée globale.
Un environnement d'exécution possède son propre
espace de variable. Pour connaître une variable dans plusieurs environnements,
il faut la déclarer à l'aide du mot réservé global.
Par exemple, une fonction ne connait pas les variables du script,
pour y remédier, on déclare celles que l'on souhaite utiliser
dans la fonction avec global.
| Exemple |
function printLink($link) {
global $color;
echo "<a style=\"color:$color;\" href=\"$link\">Visitez $link !</a>";
}
$color = "yellow";
printLink("http://www.developpez.com")
|
[ haut ]
Les tableaux superglobaux ne peuvent être utilisés qu'avec
la version PHP 4.2.0 (et supérieures).
En pratique, une variable superglobale est simplement disponible
dans tout contexte d'utilisation, que ce soit dans le script, dans une méthode
de classe, dans une fonction... sans avoir à utiliser la directive global.
Il n'est pas possible (pour l'instant du moins) de créer soi-même des variables
superglobales, on ne peut qu'utiliser celles déjà existantes comme
définies dans la Liste des tableaux superglobaux.
Ces variables sont des tableaux associatifs. C'est-à-dire qu'à une clé est associée
une valeur pouvant être un nombre, une chaîne de caractères, un tableau...
Les clés de ces tableaux sont les noms des variables qu'ils référencent.
| Exemple |
function printLink($link) {
echo "<a style=\"color:".$GLOBALS["color"].";\" href=\"$link\">Visitez $link !</a>";
}
$color = "yellow";
printLink("http://www.developpez.com")
|
Comme les tableaux superglobaux remplacent d'anciennes variables obsolètes
mais toujours présentes, ces dernières peuvent encore être utilisées.
Dans ce cas, ne pas oublier la directive global.
[ haut ]
Ces tableaux ne sont disponibles que sur les serveurs équipés de la
version 4.2.0 et suivantes de PHP. Pour les versions antérieures,
il faut utiliser les variables dites obsolètes du tableau suivant.
A noter, que certaines variables peuvent être simultanément disponibles
dans plusieurs tableaux superglobaux à la fois.
Par exemple, le tableau $GLOBALS reprend chacune des variables
disponibles dans tous les autres tableaux superblobaux.
Autre exemple, un paramètre passé dans l'URL à un script sera référencé
dans $_GET et dans $_REQUEST.
| Nom | Description | Nom obsolète |
$GLOBALS |
Contient toutes les variables disponibles dans l'environnement d'exécution global. | - |
$_SERVER |
Contient les variables fournies par le serveur web. |
$HTTP_SERVER_VARS |
$_GET |
Contient les variables fournies en paramètre au script via la méthode GET du protocole HTTP. |
$HTTP_GET_VARS |
$_POST |
Contient les variables fournies par un formulaire via la méthode POST du protocole HTTP. |
$HTTP_POST_VARS |
$_COOKIES |
Contient les variables fournies par les cookies via le protocole HTTP. |
$HTTP_COOKIE_VARS |
$_FILES |
Contient les variables fournies suite à un chargement de fichier par un formulaire via la méthode POST du protocole HTTP. |
$HTTP_POST_FILES |
$_ENV |
Contient les variables fournies par l'environnement.
Ce peut être des variables du Shell sous lequel s'exécute PHP,
les variables CGI... |
$HTTP_ENV_VARS |
$_REQUEST |
Contient les variables fournies au script par n'importe quel mécanisme. | - |
$_SESSION |
Contient les variables de la session en cours dans le script. |
$HTTP_SESSION_VARS |
[ haut ]
Ces variables sont référencées dans le tableau superglobal $_SERVER.
| Nom | Description |
argv |
Tableau des arguments passés au script dans le cas où celui-ci est
lancé en ligne de commande depuis un Shell. |
argc |
Nombre de paramètres passés au script (dans le cas ligne de commande). |
DOCUMENT_ROOT |
Racine à partir de laquelle est exécuté le script. |
PHP_SELF |
Nom du fichier du script en cours par rapport au DOCUMENT_ROOT. |
REQUEST_METHOD |
Méthode de la requète invoquée pour accéder à la page.
Avec le protocole HTTP/1.0, les méthodes possibles sont :
GET, POST, HEAD, PUT. |
REQUEST_URI |
URI (Uniform Resource Identifier) qui a été fournie pour accéder à la page. |
QUERY_STRING |
Question posée au script (si elle existe).
Ce sont les paramètres passés au script. |
SCRIPT_FILENAME |
Chemin absolu jusqu'au script courant. |
SCRIPT_NAME |
Nom du script courant.
Utilisé dans le champs method des formulaires
pour que le script s'appelle lui-même. |
PATH_TRANSLATED |
Chemin de la page dans le système de fichier réel du serveur.
Est différent du chemin virtuel traduit pour l'extérieur. |
GATEWAY_INTERFACE |
Numéro de révision de l'interface CGI du serveur. |
SERVER_NAME |
Nom du serveur qui exécute le script.
Ce peut-être un hôte virtuel.
Tel que défini par la directive VIRTUAL_HOST d'Apache. |
SERVER_SOFTWARE |
Chaîne de caractères d'identification du serveur.
Contenu du champs Server de l'entête HTTP.
Par exemple : Apache/1.3.9 (Unix) Debian/GNU. |
SERVER_PROTOCOL |
Nom et révision du protocole utilisé pour transférer au client la page issue du script.
En général : HTTP/1.0 ou HTTP/1.1. |
SERVER_ADMIN |
Identifiant de l'administrateur du serveur tel que défini
par la directive SERVER_ADMIN d'Apache. |
SERVER_PORT |
Numéro de port utilisé sur le serveur.
Traditionnellement, vaut 80. |
SERVER_SIGNATURE |
Chaîne de caractères contenant le numéro de version du serveur
ainsi que le nom d'hôte virtuel. |
HTTP_ACCEPT |
Contenu du champs Accept de l'entête HTTP.
C'est la liste des types MIME.
Par exemple : text/html, application/xml, image/gif. |
HTTP_ACCEPT_CHARSET |
Contenu du champs Accept-Charset de l'entête HTTP.
C'est le type d'encodage des caractères utilisé. |
HTTP_ACCEPT_ENCODING |
Contenu du champs Accept-Encoding de l'entête HTTP.
C'est le type d'encodage des données utilisé.
C'est en général de la compression.
Par exemple : gzip. |
HTTP_ACCEPT_LANGUAGE |
Contenu du champs Accept-Language de l'entête HTTP.
C'est la langue utilisée. Par exemple : fr. |
HTTP_CONNECTION |
Contenu du champs Accept-Connection de l'entête HTTP.
C'est le type de la connexion établie entre le client et le serveur (persistente ou non),
par exemple : Keep-Alive ou close. |
HTTP_HOST |
Contenu du champs Host de l'entête HTTP en cas de virtual hosting. |
HTTP_REFERER |
Adresse de la page qui a conduit le client à la page courante. |
HTTP_USER_AGENT |
Contenu du champs User-Agent de l'entête HTTP.
C'est le nom et la version du navigateur utilisé par le client
pour consulter la page en cours. Ainsi que le système
d'exploitation et autres informations.
Par exemple : Mozilla/5.0 Galeon/1.0.2 (X11;Linux i686; U;) Gecko/20011224. |
REMOTE_ADDR |
Adresse IP du client qui demande la page. |
REMOTE_PORT |
Le numéro de port utilisé sur la machine cliente pour
établir la communication avec le serveur. |
| Script de départ |
echo "<form action=\"".$_SERVER["SCRIPT_NAME"]."\" method=\"POST\">";
echo "<input type=\"text\" name=\"nom\" />";
echo "<input type=\"submit\" />";
echo "</form>";
|
| Script d'arrivée |
echo "Vous êtes ".$_POST["nom"].".";
|
[ haut ]
On a vu qu'à partir de PHP 4.2.0 les variables référencées dans les tableaux superglobaux
ne sont accessibles que par l'intermédiaire de ces tableaux.
Auparavant, les variables référencées pouvaient être accédées directement,
via un global si nécessaire (dans les fonctions et méthodes).
Ce changement repose sur un paramètrage par défaut du fichier de configuration
php.ini qui a été changé.
Le paramètre register_global était à On, en PHP 4.2.0
il passe à Off par défaut.
Mais il est toujours possible de le changer manuellement afin de revenir à la situation
antérieure ou les variables référencées par ces tableaux superglobaux étaient
directement accessibles.
Avec register_global = On, appel de la page page.php?id=41&nom=robert
: |
<?php
function afficher() {
global $nom
echo "Vous êtes ".$nom;
}
echo "$id, $nom";
afficher();
?>
|
Affiche :
41, robert
Vous êtes robert
|
Avec register_global = Off, appel de la page page.php?id=41&nom=robert
: |
<?php
function afficher() {
echo "Vous êtes ".$_GET["nom"];
}
echo $_GET["id"].", ".$_GET["nom"];
afficher();
?>
|
Affiche :
41, robert
Vous êtes robert
|
[ haut ]
Pourquoi avoir introduit cette nouveauté dans PHP 4.2.0 ?
Tout simplement pour des raisons de sécurité.
Non pas que PHP lui-même comporte des failles de sécurité
(en fait si, mais c'est pas le sujet de cet article),
mais les webdesigners qui programment en PHP ne font pas toujours
suffisamment attention à ce qu'ils écrivent.
Permettant ainsi aux internautes malveillants d'induire
le script en erreur ou de lui faire faire des choses
qui n'étaient pas prévues.
Voici un petit exemple, notre script script.php
va inclure un fichier de configuration via une commande include()
qui contient par exemple les informations nécessaires (login, mot de passe, nom de la base)
pour se connecter à une base de données MySQL.
Le nom de ce fichier est normalement passé en paramètre via un formulaire (méthode GET ou POST).
script.php |
<?php
include($config_file);
...
?>
|
Un petit malin pourait avoir l'idée d'aller regarder le code source HTML
de votre formulaire formulaire.php.
formulaire.php |
<form action="script.php" method="POST">
<input type="hidden" name="config_file" value="config_bd.php" />
|
Libre à lui, à partir de là, d'exécuter votre script d'arrivée
sans passer par l'intermédiaire du formulaire, et en lui passant des
paramètres en argument.
| Adresse tapée dans le navigateur par le hacker : |
script.php?config_file=/etc/passwd
|
Ainsi votre script a été détourné pour afficher le fichier de mot de passe
du serveur ! Il connait maintenant tous les utilisateurs de votre système
(les mots de passe sont généralement cryptés).
Les include() préfixés ou suffixés par une chaîne de caractères
constante ne sont pas mieux lotis.
Dans l'exemple suivant, un chemin relatif permet la remontée dans le système de fichiers.
script.php?config_file=../../../etc/passwd |
include("common/config/$config_file");
|
Dans l'exemple suivant, une chaîne de caractères terminée par le caractère spécial
de fin de chaîne %00 dit à PHP d'ignorer le suffixe "inc".
script.php?config_file=../../etc/passwd%00 |
include("myfiles/".$config_file."inc");
|
Comment remédier à ces attaques ?
En étant plus rigoureux dans sa programmation !
L'exemple suivant montre une méthode sûre.
script.php |
<?php
$files = array{"config_db.php", "config_user.php", "config_forum.php"}
if(in_array($config_file,$files)) {
require($config_file);
} else {
echo "C'est pas beau de pirater les sites web !";
}
?>
|
Dans cet exemple, on vérifie que le nom de fichier reçu par le script
appartient à une liste prédéterminée, si tel est le cas, on l'inclu.
Sinon, c'est qu'il y a un problème !
Il existe de nombreuses fonctions travaillant sur les fichiers qui sont
succeptibles d'être détournées (inclusion, ouverture, exécution de fichier):
require(), include(), include_once(),
require_once(), file(), readfile(),
fpassthru(), exec(), fopen()...
Il est donc nécessaire d'être très vigilant lors de la programmation en PHP
et de deviner quelles sont toutes les actions malveillantes succeptibles
d'êtres exécutées à travers vos scripts. Il s'agit donc d'être particulièrement paranoïaque
et de protéger toutes les variables en les vérifiant systématiquement.
D'ailleurs ce problème n'est pas réservé aux fichiers.
Toutes les autres variables sont consernées. Ainsi les id de sessions
peuvent être falsifiées, les id de message à supprimer d'un forum aussi...
Alors, au lieu de faire démesurément confiance aux variables créée
automatiquement dans l'espace d'exécution (par global_register)
à partir des paramètres passés au script, on utilise les tableaux globaux
$HTTP_ENV_VARS, $HTTP_GET_VARS
$HTTP_POST_VARS, $HTTP_COOKIE_VARS,
$HTTP_SERVER_VARS et $HTTP_SESSION_VARS
(créés automatiquement par la directive de configuration track_vars
mise à On).
Ainsi, utiliser $HTTP_POST_VARS["config_file"] permet de se prémunir
contre les attaques précédentes.
Par contre cette relative sécurité peut être détournée par un hacker
qui enregistre sur son ordinateur votre formulaire, en modifie le code
pour changer le
<input type="hidden" name="config_file" value="config_bd.php" />
en
<input type="hidden" name="config_file" value="/etc/passwd%00" />
et valider le formulaire pour vous pirater !
Depuis PHP 4.2.0 ces tableau globaux sont devenus obsolètes.
Et il faut alors utliser les tableaux superglobaux.
[ haut ]
Sur PHP.net :
- Tableaux superglobaux de PHP
- Variables de serveur : $_SERVER
- Variables Apache
- Portée des variables
Pour de plus amples informations sur cette question de sécurité,
je vous recommande la lecture de cet article de Thomas Oertli :
Secure Programming in PHP
(en anglais).
Un autre document très intéressant, traduit en français celui-là,
Exploitation des vulnérabilités avec les applications PHP
de Shaun Clowes SecureReality.
[ haut ]
|