11.Programmer en PHP en toute sécurité

11.3.Injection SQL

11.3.1.Ce qu'il faut faire/ne pas faire

Si vous construisez un requête SQL à partir d'informations saisies par vos visiteurs (ce qui est quasiment tout le temps le cas) vous devez absolument vérifier les paramètres, et tout particulièrement pour les fonctions permettant l'execution de plusieurs requêtes à la fois (comme avec SQLite).

11.3.2.Pourquoi?

Prenons par exemple, une requête SQL construite de la façon suivante:
<?php
$sql = 'SELECT * FROM matable WHERE age='.$age;
?>
où $age peut être précisé par l'utilisateur (typiquement via un formulaire).
S'il n'y a aucun contrôle d'effectué sur les champs (ici, $age) alors l'utilisateur pourra saisir non pas une valeur attendue comme "24" par exemple mais plutôt "24; DROP TABLE matable". Si la fonction chargée d'exécuter la requête SQL permet d'exécuter plusieurs requêtes à la fois alors, je vous laisse imaginer le résultat.... et hop, toutes les données sont effacées.
Dans ce cas, le contrôle est très simple: il suffit de vérifier que la valeur saisie est bien de type entier. On pourra faire un test du genre
<?php
if (!is_numeric($age)) die('Valeur invalide');
?>
Cela peut être un peu plus complexe si la valeur du champ impliqué dans la requête est censée être de type chaîne de caractères. Cependant, dans ce cas, la requête SQL devrait plutôt être similaire à la suivante
<?php
$sql = 'SELECT * FROM matable WHERE nom=\''.$nom.'\'';
?>
Du fait de la présence des apostrophes, le valeur saisie par le pirate devra plutôt être similaire à "blabla'; DROP TABLE matable".
Normalement, pour que votre code soit suffisamment robuste, les chaînes de caractères doivent être traitées pour "échapper" les apostrophes (et éventuels autres caractères spéciaux). Ceci se fait avec la fonction addSlashes(), les fonctions MySQL[où?] mysql_real_escape_string(), real_escape_string(), MySQLi::escape_string() ou avec la fonction SQLite[où?] sqlite_escape_string() ou autres, selon les bases de données. Si tel est le cas alors la chaîne saisie par le pirate est transformée en "blabla\'; DROP TABLE matable" ou "blabla''; DROP TABLE matable" (selon les cas) ce qui fait qu'au final la tentative de piratage ne peut aboutir.
Notez cependant que de nombreuses fonctions ne permettent pas d'exécuter plusieurs instructions SQL en même temps. Mais ce n'est pas une raison pour ne pas prendre de bonnes habitudes (et de toutes façons les fonctions de type _escape_string sont indispensables pour stocker des valeurs pouvant contenir des apostrophes.

11.3.3.Conclusion

Il faut s'assurer que les champs censés être de type numérique sont bien de type numérique et appliquer les fonctions d'échappement à toutes les autres valeurs, en prenant bien soin de délimiter, dans les requêtes SQL, ces valeurs par des guillemets.