Une case de recherche trop bavarde
Une enseigne de bricolage a une case de recherche sur son site. Un jour, quelqu’un y tape un texte étrange, plein d’apostrophes.
Le site affiche alors la liste complète de ses clients. Le développeur avait écrit une seule ligne imprudente.
Cette leçon montre comment une simple saisie peut changer ce que fait un programme.
À la fin de cette leçon
Remarque
Je peux expliquer comment fonctionnent l’injection et le cross-site scripting.
Mots clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Entrée | ce qu’un utilisateur tape ou envoie | |
| Requête SQL | une question posée à une base de données | SELECT nom FROM clients |
| Injection | une entrée qui devient une partie de la commande | |
| XSS | une entrée qui devient une partie de la page | |
| Paramètre | une place réservée pour une valeur | ? |
| Échapper | transformer les caractères spéciaux en simple texte | < |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
L’injection transforme une saisie en commande
Beaucoup d’applis construisent une requête SQL avec ce que vous tapez. Une appli imprudente colle votre entrée directement dans le texte de la requête.
Si l’entrée contient une apostrophe, elle peut fermer la valeur trop tôt. La suite devient alors une partie de la commande.
C’est l’injection SQL. Lancez la requête ci-dessous sur une table d’essai.
Essayez : la requête qui a tourné
-- L'appli devait trouver un seul client par son e-mail.
-- Quelqu'un a tapé ceci dans la case e-mail : ' OR '1'='1
-- L'appli l'a collé dans la requête, et voici ce qui a tourné :
SELECT nom, email, ville FROM clients
WHERE email = '' OR '1'='1';
-- Lancez-la. Puis remplacez la ligne WHERE par : WHERE email = '[email protected]';
Un paramètre garde l’entrée à sa place
La parade est simple. Écrivez la requête avec un paramètre, le point d’interrogation, à la place de la valeur.
La base reçoit la requête et la valeur séparément. L’entrée ne peut donc jamais devenir du SQL, même avec des apostrophes.
Comparez les deux façons dans le code ci-dessous.
Essayez : collée ou en paramètre
import sqlite3
base = sqlite3.connect(":memory:")
base.execute("CREATE TABLE clients (nom TEXT, email TEXT)")
base.execute("INSERT INTO clients VALUES ('Camille Roux', '[email protected]')")
base.execute("INSERT INTO clients VALUES ('Mehdi Benali', '[email protected]')")
tape = "' OR '1'='1"
# Dangereux : l'entrée devient une partie du SQL
collee = "SELECT nom FROM clients WHERE email = '" + tape + "'"
print("Collée :", base.execute(collee).fetchall())
# Sûr : le ? est un paramètre, l'entrée reste une simple valeur
sure = "SELECT nom FROM clients WHERE email = ?"
print("Paramètre :", base.execute(sure, [tape]).fetchall())
# Remplacez tape par "[email protected]", puis relancez.
Le XSS fait d’un texte du code
Le même piège existe dans les pages web. Un site affiche les avis de ses clients.
Si un avis contient une balise <script>, le navigateur la lit comme du code. Ce code tourne chez chaque visiteur, avec sa session ouverte. C’est le XSS, ou cross-site scripting.
La parade est d’échapper le texte avant de l’afficher. Le navigateur montre alors les signes au lieu de les exécuter.
Essayez : échapper un avis
import html
avis = "<script>alert('coucou')</script> Livraison rapide"
# Dangereux : l'avis entre dans la page tel quel
print("<p>" + avis + "</p>")
# Sûr : escape transforme < et > en texte que le navigateur affiche seulement
print("<p>" + html.escape(avis) + "</p>")
# Essayez un avis qui contient <b>gras</b>.
Une erreur fréquente
Attention
Beaucoup pensent qu’il suffit d’interdire le mot SELECT ou la balise script. Un attaquant trouve toujours une autre écriture. Utilisez des paramètres en SQL et échappez tout texte affiché, car ces deux méthodes marchent quelle que soit l’entrée.