|
Le langage Perl n'est
pas en soi un langage "à risque": le problème
vient de son utilisation sous forme de scripts CGI, utilisation
qui impose au programmeur d'être vigilant, car des fonctionnalités
du Perl mal utilisées peuvent constituer (du fait du développeur,
non du langage lui-même, répétons-le) des dangers
pour la sécurité des données.
Exécution de commandes système
ou de programmes externes
Il convient notamment de prendre ses précautions avec certaines
fonctions utilisées pour exécuter des programmes externes
ou des commandes: les fonctions exec() et system():
cette dernière admet plusieurs paramètres, le premier
étant interprété comme une commande à
exécuter, les suivants comme des arguments. Ainsi, imaginons
que nous devons développer un CGI qui demande son identifiant
à un utilisateur pour lui renvoyer le contenu d'un fichier
de données le concernant. On pourrait écrire:
$user
= param("identifiant");
system ("cat /usr/donnes/$user");
La commande exécutée si l'utilisateur spécifie,
dans le champ "identifiant", la chaîne "monnom"
est alors la suivante:
cat /usr/donnees/monnom
Mais si la chaîne spécifiée est "monnom;
rm -rf", la commande exécutée est alors:
cat /usr/donnees/monnom; rm -rf
Avec les conséquences qu'on imagine...
Il aurait fallu écrire:
system("cat", "/usr/donnees/$user");
ainsi la chaîne "monnom; rm -rf" sera interprétée
comme un nom de fichier, et ne causera pas de catastrophe!
Malgré cela, il reste encore possible à un malveillant
de transmettre la chaîne "../../etc/passwd"...
Ainsi, system() (et exec(), fonction à laquelle ce que nous
venons d'écrire s'applique également), sont à
manier avec la plus grande précaution.
D'une manière générale, toute instruction invoquant
un shell est une instruction à risque: il est très
souvent possible, plutôt que de devoir appeler un programme
externe, d'utiliser une extension (module) au langage Perl.
Au lieu d'utiliser la commande Unix cat, nous allons, plus traditionnellement,
ouvrir un fichier avec la fonction Perl open():
open (DONNEES, "</usr/donnees/$user);
puis lire les données au moyen d'instructions Perl.
Les
autres problèmes de sécurité
Parmi eux figurent notamment (mais il y en a d'autres), la
fonction rand() qui est utilisée pour engendrer des
nombres aléatoires: cette fonction produit en fait une séquence
de nombres pseudo-aléatoires à partir d'une certaine
valeur initiale: cette valeur initiale permet de connaître
la séquence de nombres qui sera produite par rand(). Si la
fonction est utilisée pour de la cryptographie, ceci est
assez problématique car les hackers, s'ils ont accès
à des informations ponctuelles sur la séquence, pourront
reconstituer celle-ci.
Enfin, un risque de sécurité est créé
par des portions de code, apparemment inoffensives, comme la suivante:
unless (-e "/tmp/monfichier")
{
open (FICHIER, ">/tmp/monfichier");
}
Ce code vient tester l'existence du fichier /tmp/monfichier, et
si celui-ci n'existe pas, il le crée et le rend disponible
pour l'écriture (caractère ">").
Un hacker expérimenté, qui aurait accès
au code source, pourrait se lancer dans une "course de vitesse"
avec le programme, qui constitue ce qu'en anglais on appelle une
"race condition". En effet, si notre hacker
est capable de faire exécuter sur le serveur la commande
suivante, entre le moment où la vérification de
l'existence de /tmp/monfichier a été effectuée
sans succès (le fichier n'existant pas), et le moment
où ce fichier est rendu disponible pour l'écriture:
ln -s /tmp/monfichier /etc/fichier_de_configuration_important
Toutes les modifications apportées théoriquement à
/tmp/monfichier le seront désormais au fichier de configuration
important. Il s'agit là d'un véritable "détournement".
On le voit, le développeur n'est jamais trop prudent, d'autant
que la liste des dangers possibles ne s'arrête pas, loin de
là, à ce que nous venons d'évoquer. Une programmation
rigoureuse et une bonne connaissance des systèmes sont les
seules solutions pour se mettre à l'abri des attaques.
|