Envoyé par unreal
Le PHP n'a pas une très bonne réputation en matière de sécurité. Cette mauvaise réputation est souvent le résultat de négligence de la part des développeurs qui ne prennent pas systématiquement les mesures nécessaires pour renforcer la sécurité des sites. Alors voici un petit guide qui rappelle les règles de base.
Surveiller vos variables !
Une des bêtes noires des programmeurs vient du fait que le PHP est un langage non-typé, ce qui veut dire qu'il n'est pas possible de définir le type (int, string...) des variables avant utilisation. Ainsi, une requête SQL comme celle qui suit est très dangereuse :
La solution est d'utiliser des casts. Par exemple :
L'autre bête noire est l'oubli fréquent des addslashes dans les requêtes SQL.
Par exemple :
Ceci est aussi très dangereux car si jamais '$Nom_Utilisateur' contient un apostrophe, non seulement la requête va échouer, mais en plus il est possible de réaliser une injection SQL, qui pourrait donner au malfaiteur accès complet à la base. Je conseille, donc, de placer les addslashes directement au niveau des requêtes pour éviter de se retrouver avec des \' sur la page Web elle même :
Sécurité HTML
Ce n'est pas vraiment une très bonne idée d'autoriser les visiteurs d'un site à saisir directement du HTML car filtrer convenablement ce dernier n'est pas chose facile.
Sans filtrage, le visiteur pourrait insérer du code javascript pour essayer de récupérer des informations sensibles (session PHP) ou pour installer des spywares.
Hélas, filtrer du HTML requière des bonnes connaissances en HTML. Supposons par exemple qu'on autorise la balise <div> pour les blocs de quote (<div class="quote">...</div>), qu'est ce qui empêcherait un visiteur à saisir <div style="...">...</div> ?
Du coup, il faudrait détecter qu'il s'agit bien d'une classe de div autorisée, mais le visiteur pourrait essayer de contourner en mettant <div class="quote" style="font: normal 200pt;">...</div> (notez que ceci est un exemple de HTML non valide, mais qui fonctionne sur certains browsers).
Il faut aussi penser à corriger les erreurs HTML (volontaires ou non) comme les balises laissées ouvertes ou encore les erreurs de syntaxe (comme dans l'exemple précédent).
Toute cette explication pour dire que j'encourage vivement à exploiter un système à base de BBCode qui permet bien plus de contrôle et de sécurité.
Pour info, la classe BBCode qui anime SlashOrg.Net est disponible à cette adresse.
Sécurisation des informations sensibles
Cela peut paraître incroyable, mais il existe encore aujourd'hui des sites qui ne sécurisent pas les informations sensibles des utilisateurs (comme le mot de passe) ; en clair, un site où on vous propose d'envoyer un mot de passe oublié par mail est un site qui ne sécurise pas les mots de passe. La conséquence directe est que n'importe quelle personne ayant accès à la base de données (légitimement ou en exploitant des failles de codage ou de sécurité) peut lire en clair les mots de passe. Ceci est évidemment une mauvaise chose.
Alors qu'est ce qu'on entend par sécurisation ? La méthode la plus simple consiste à hasher les mots de passe avant de les enregistrer dans la base. Le hashage fait intervenir une fonction de codage à sens unique : il est donc impossible (en principe) de retrouver un mot de passe à partir de son hash. En réalité, la seule manière de retrouver le mot de passe est d'essayer toutes les combinaisons, qui peut prendre un temps considérable du moment où on utilise des mots complexes.
L'algo de hashage le plus courant en PHP s'appelle le MD5 (128 bits), mais sachez qu'il en existe d'autres (SHA1, par exemple, offre un codage 160 bits).
Fonctionnement : dans un premier temps, quand l'utilisateur s'inscrit, on stocke son mot de passe sous forme de hash dans la base.
Ensuite, quand l'utilisateur se logge, on hash à nouveau son mot de passe et on compare à la valeur contenue dans la base :
Pour exploiter le hashage SHA1, il suffit de remplacer md5() par sha1().
Les sessions
Quand un utilisateur se connecte, il faut pouvoir le "suivre" sur le site pour lui proposer les options adéquates. Pour cela, il convient d'employer les sessions PHP qui permettent de s'assurer que l'utilisateur est bien celui qu'il prétend être. Concrètement, le PHP va envoyer un cookie de session au browser client et stocker une copie de cette session sur le disque du serveur. Ainsi, si jamais l'utilisateur modifie son cookie, la session sera automatiquement détruite. Cette méthode offre donc un excellent niveau de sécurité (tant que le pirate n'arrive pas à intercepter le cookie en sniffant le réseau, par exemple).
Exemple d'utilisation :
Dans tous les cas, il ne faut jamais stocker des informations sensibles (user ID, nom d'utilisateur, niveau d'utilisateur) dans un cookie non sécurisé, parce que dans ce cas, il est très facile à un utilisateur de modifier le cookie pour se faire passer pour quelqu'un d'autre (un administrateur).
Fin
Comme toujours, n'hésitez pas à faire part de vos remarques.
Surveiller vos variables !
Une des bêtes noires des programmeurs vient du fait que le PHP est un langage non-typé, ce qui veut dire qu'il n'est pas possible de définir le type (int, string...) des variables avant utilisation. Ainsi, une requête SQL comme celle qui suit est très dangereuse :
<?php
$id = $_GET['post_id']; // N'est pas forcément un (int)
// Sans être sûr que $id un (int) on s'expose à de gros soucis !
$sql = 'SELECT c1, c2, c3 FROM t1 WHERE id = ' . $id;
?>
$id = $_GET['post_id']; // N'est pas forcément un (int)
// Sans être sûr que $id un (int) on s'expose à de gros soucis !
$sql = 'SELECT c1, c2, c3 FROM t1 WHERE id = ' . $id;
?>
La solution est d'utiliser des casts. Par exemple :
$id = (int)$_GET['post_id']; // $id est forcément un (int)
L'autre bête noire est l'oubli fréquent des addslashes dans les requêtes SQL.
Par exemple :
<?php
$Nom_Utilisateur = $_POST['nom'];
$sql = "SELECT c1, c2, c3 FROM t1 WHERE UserName = '$Nom_Utilisateur'";
?>
$Nom_Utilisateur = $_POST['nom'];
$sql = "SELECT c1, c2, c3 FROM t1 WHERE UserName = '$Nom_Utilisateur'";
?>
Ceci est aussi très dangereux car si jamais '$Nom_Utilisateur' contient un apostrophe, non seulement la requête va échouer, mais en plus il est possible de réaliser une injection SQL, qui pourrait donner au malfaiteur accès complet à la base. Je conseille, donc, de placer les addslashes directement au niveau des requêtes pour éviter de se retrouver avec des \' sur la page Web elle même :
$sql = "SELECT c1, c2, c3 FROM t1 WHERE UserName = '" . addslashes($Nom_Utilisateur) . "'";
Sécurité HTML
Ce n'est pas vraiment une très bonne idée d'autoriser les visiteurs d'un site à saisir directement du HTML car filtrer convenablement ce dernier n'est pas chose facile.
Sans filtrage, le visiteur pourrait insérer du code javascript pour essayer de récupérer des informations sensibles (session PHP) ou pour installer des spywares.
Hélas, filtrer du HTML requière des bonnes connaissances en HTML. Supposons par exemple qu'on autorise la balise <div> pour les blocs de quote (<div class="quote">...</div>), qu'est ce qui empêcherait un visiteur à saisir <div style="...">...</div> ?
Du coup, il faudrait détecter qu'il s'agit bien d'une classe de div autorisée, mais le visiteur pourrait essayer de contourner en mettant <div class="quote" style="font: normal 200pt;">...</div> (notez que ceci est un exemple de HTML non valide, mais qui fonctionne sur certains browsers).
Il faut aussi penser à corriger les erreurs HTML (volontaires ou non) comme les balises laissées ouvertes ou encore les erreurs de syntaxe (comme dans l'exemple précédent).
Toute cette explication pour dire que j'encourage vivement à exploiter un système à base de BBCode qui permet bien plus de contrôle et de sécurité.
Pour info, la classe BBCode qui anime SlashOrg.Net est disponible à cette adresse.
Sécurisation des informations sensibles
Cela peut paraître incroyable, mais il existe encore aujourd'hui des sites qui ne sécurisent pas les informations sensibles des utilisateurs (comme le mot de passe) ; en clair, un site où on vous propose d'envoyer un mot de passe oublié par mail est un site qui ne sécurise pas les mots de passe. La conséquence directe est que n'importe quelle personne ayant accès à la base de données (légitimement ou en exploitant des failles de codage ou de sécurité) peut lire en clair les mots de passe. Ceci est évidemment une mauvaise chose.
Alors qu'est ce qu'on entend par sécurisation ? La méthode la plus simple consiste à hasher les mots de passe avant de les enregistrer dans la base. Le hashage fait intervenir une fonction de codage à sens unique : il est donc impossible (en principe) de retrouver un mot de passe à partir de son hash. En réalité, la seule manière de retrouver le mot de passe est d'essayer toutes les combinaisons, qui peut prendre un temps considérable du moment où on utilise des mots complexes.
L'algo de hashage le plus courant en PHP s'appelle le MD5 (128 bits), mais sachez qu'il en existe d'autres (SHA1, par exemple, offre un codage 160 bits).
Fonctionnement : dans un premier temps, quand l'utilisateur s'inscrit, on stocke son mot de passe sous forme de hash dans la base.
$password = md5($_POST['password']);
$sql = "INSERT INTO users VALUES (..., '$password', ...)";
$sql = "INSERT INTO users VALUES (..., '$password', ...)";
Ensuite, quand l'utilisateur se logge, on hash à nouveau son mot de passe et on compare à la valeur contenue dans la base :
<?php
$username = addslashes($_POST['username']);
$password = md5($_POST['password']);
$sql = "SELECT username FROM users WHERE username = '$username' AND password = '$password'";
[...] // On recupère le nombre d'entrées dans $no
if ($no == 1) {
$login_ok = true;
} else {
$login_ok = false;
}
?>
$username = addslashes($_POST['username']);
$password = md5($_POST['password']);
$sql = "SELECT username FROM users WHERE username = '$username' AND password = '$password'";
[...] // On recupère le nombre d'entrées dans $no
if ($no == 1) {
$login_ok = true;
} else {
$login_ok = false;
}
?>
Pour exploiter le hashage SHA1, il suffit de remplacer md5() par sha1().
Les sessions
Quand un utilisateur se connecte, il faut pouvoir le "suivre" sur le site pour lui proposer les options adéquates. Pour cela, il convient d'employer les sessions PHP qui permettent de s'assurer que l'utilisateur est bien celui qu'il prétend être. Concrètement, le PHP va envoyer un cookie de session au browser client et stocker une copie de cette session sur le disque du serveur. Ainsi, si jamais l'utilisateur modifie son cookie, la session sera automatiquement détruite. Cette méthode offre donc un excellent niveau de sécurité (tant que le pirate n'arrive pas à intercepter le cookie en sniffant le réseau, par exemple).
Exemple d'utilisation :
<?php
session_start(); // Initialise la session
$_SESSION['nom_de_ma_session'] = 'blablabla'; // Ecriture dans la session
[...]
$ses = $_SESSION['nom_de_ma_session']; // Lecture de la session
[...]
session_unset(); // Libération de toutes les variables de session
session_destroy(); // Destruction de la session
?>
session_start(); // Initialise la session
$_SESSION['nom_de_ma_session'] = 'blablabla'; // Ecriture dans la session
[...]
$ses = $_SESSION['nom_de_ma_session']; // Lecture de la session
[...]
session_unset(); // Libération de toutes les variables de session
session_destroy(); // Destruction de la session
?>
Dans tous les cas, il ne faut jamais stocker des informations sensibles (user ID, nom d'utilisateur, niveau d'utilisateur) dans un cookie non sécurisé, parce que dans ce cas, il est très facile à un utilisateur de modifier le cookie pour se faire passer pour quelqu'un d'autre (un administrateur).
Fin
Comme toujours, n'hésitez pas à faire part de vos remarques.
Posté le 10/06/05 à 04:49