Chapitre 29. Utilisation des variables super-globales

L'une des évolutions les plus controversées de PHP a été le changement de valeur par défaut de la directive PHP register_globals, qui est passée de On à Off en PHP 4.2.0. Beaucoup d'applications dépendaient de cette directive, et de nombreux programmeurs ne savaient même pas qu'elle existait, et supposait que c'était le fonctionnement normal de PHP. Cette page explique comment on peut écrire du code peu sécuritaire en utilisant cette directive. Gardez bien en tête que cette directive, par elle-même, n'est pas un trou de sécurité, mais qu'elle facilite leur création.

Lorsqu'elle est activée, register_globals va injecter (empoisonner) vos scripts avec toutes sortes de variables, comme les variables issues des formulaires HTML. Ceci, couplé au fait que PHP ne requiert pas d'initialisation de variable signifie que la programmation de script peu sûr est possible. Ce fut une décision difficile de la communauté PHP, mais finalement, il a été décidé de désactiver par défaut cette variable. Lorsqu'elle est active, le programmeur ne sait pas exactement d'où provient le contenu de la variable, et ne peut que faire des suppositions. Les variables internes définies dans le script sont mélangées avec les données envoyées par les utilisateurs, et en désactivant register_globals, on empêche cela. Voyons avec un exemple le fonctionnement de register_globals :

Exemple 29-1. Exemple de mésutilisation de register_globals = on

<?php
// $authorized = true uniquement si l'utilisateur est identifié
if (authenticated_user()) {
    
$authorized = true;
}

// Comme nous n'avons pas initialisé $authorized avec false, cette dernière
// peut être définie via register_globals, comme avec l'URL GET auth.php?authorized=1
// Tout le monde peut facilement être reconnu comme identifié!
if ($authorized) {
    include
"/donnees/critiques/data.php";
}
?>

Lorsque register_globals est activé, la logique ci-dessus peut être prise en défaut. Lorsque register_globals est désactivée $authorized ne peut plus être assignée via la requête, et le script est maintenant sûr, même s'il reste recommandé de toujours initialiser ses variables. Par exemple, dans notre programme ci-dessus, nous pourrions ajouter $authorized = false. En faisant cela, le script peut fonctionner avec register_globals on ou off, car les utilisateurs seront par défaut non-identifiés.

Un autre exemple implique les sessions. Lorsque register_globals est activé, on peut aussi utiliser $username dans notre exemple, mais, encore une fois, vous devez garder en tête que $username peut aussi provenir d'autres biais, tels que GET (via l'URL).

Exemple 29-2. Exemple d'abus de sessions avec register_globals on ou off

<?php
// Nous ne savons pas d'où provient $username mais nous savons que
// $_SESSION contient les données de session
if (isset($_SESSION['username'])) {

    echo
"Bonjour <strong>{$_SESSION['username']}</strong>";

} else {

    echo
"Bonjour <strong>visiteur</strong><br />";
    echo
"Voulez-vous vous identifier?";

}
?>

Il est même possible de prendre des mesures préventives, pour être alerté lorsqu'une tentative d'usurpation est faite. Si vous savez à l'avance de quelle variable le nom d'utilisateur doit provenir, vous pouvez vérifier si les données que vous manipulez sont d'une origine contrôlée. Même si cela ne garantit pas que les données ne puissent être falsifiées, cela complique la tache du faussaire. Si vous ne vous préoccupez pas de l'origine des données, vous pouvez utiliser la variable $_REQUEST qui contient un mélange de données GET, POST et COOKIE. Voyez aussi la section du manuel concernant les variables externes à PHP.

Exemple 29-3. Détection simple de fausses variables

<?php
if (isset($_COOKIE['MAGIC_COOKIE'])) {

    
// MAGIC_COOKIE provient d'un cookie.
    // Assurez-vous de valider les données du cookie!

} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {

   
mail("admin@example.com", "Tentative possible d'attaque", $_SERVER['REMOTE_ADDR']);
   echo
"Alerte sécurité, l'admin a été prévenu.";
   exit;

} else {

   
// MAGIC_COOKIE ne provient pas de REQUEST

}
?>

Bien sur, désactiver l'option register_globals ne signifie pas que votre code est sécuritaire. Pour chaque donnée reçu, vous devez appliquer un maximum de validations. Vérifiez toujours les données de votre visiteur, et initialisez vos variables! Pour vérifier les variables non-initialisées, voyez la fonction error_reporting(), qui peut afficher les erreurs de niveau E_NOTICE.

Pour des informations sur l'émulation de register_globals On ou Off, voyez la FAQ.

Superglobales : disponiblité : Depuis PHP 4.1.0, les tableaux superglobaux tels que $_GET, $_POST et $_SERVER, etc. sont disponibles. Pour plus d'informations, lisez la section superglobals