Accéder au laboratoire pratique et aux trois nouveaux exercices corrigés
Chapitre 7 sur 8. Comprendre contrôle d’accès, injections, XSS, secrets et dépendances avec un programme local de requête SQL paramétrée.
Objectifs du chapitre
- Repérer les frontières de confiance d’une application.
- Distinguer validation, paramétrage SQL et encodage HTML.
- Vérifier une autorisation côté serveur.
1. Toute entrée extérieure doit être traitée
Une application reçoit des informations provenant du navigateur, d’API, de fichiers et de services tiers. Un champ de formulaire ne garantit ni le type ni la taille du contenu envoyé. Une vérification dans le navigateur améliore l’expérience, mais le serveur doit appliquer ses propres contrôles : type attendu, longueur, format et règles métier.
Une frontière de confiance est un passage où les hypothèses de sécurité changent : navigateur vers serveur, serveur vers base ou application vers service externe. Chez GeniusCampus, le navigateur peut demander un dossier ; il ne décide pas lui-même à quel étudiant il appartient. L’application doit établir l’identité et les droits avant de renvoyer les données.
Le Top 10 OWASP 2025 est un document de sensibilisation aux risques applicatifs, pas une certification ni une liste suffisante pour auditer tout un système. Il cite notamment le contrôle d’accès, la configuration, la chaîne d’approvisionnement logicielle, la cryptographie et les injections. Nous étudions ici quelques mécanismes pour construire un raisonnement de défense.
2. Contrôle d’accès : la permission porte sur l’objet
Supposons qu’un étudiant demande le dossier numéro 42. L’application doit vérifier que cet objet est accessible à cet utilisateur, pas seulement que le numéro est valide ou que la personne est connectée. Modifier un identifiant dans une requête ne doit pas donner accès au dossier d’un autre étudiant.
Le contrôle se fait côté serveur et pour chaque opération : lire, modifier, exporter ou supprimer. Un identifiant difficile à deviner réduit parfois la découverte, mais il ne remplace pas la permission. Les essais de validation utilisent plusieurs comptes fictifs : un propriétaire, un autre utilisateur, un administrateur autorisé et un visiteur non connecté.
Une règle de refus par défaut simplifie le raisonnement : sans permission justifiée, l’opération échoue. La vérification du contrôle d’accès est testable : le propriétaire peut lire son dossier, l’autre étudiant reçoit un refus et aucun contenu sensible n’est envoyé dans la réponse.
3. Injection SQL : séparer instruction et données
Une injection devient possible lorsqu’une donnée non fiable est interprétée comme une partie d’une instruction. Pour SQL, concaténer directement le contenu d’un formulaire à une requête peut modifier sa signification. Une requête paramétrée transmet les valeurs séparément de la structure SQL ; la valeur reste une donnée.
Programme Python 3 complet, sans dépendance externe : il utilise une base SQLite en mémoire et des données fictives. Enregistrez-le sous recherche_sure.py et lancez python recherche_sure.py. Essayez un nom connu puis un nom contenant une apostrophe. Aucun serveur ni compte réel n’est utilisé.
import sqlite3
def main():
connexion = sqlite3.connect(":memory:")
try:
connexion.execute(
"CREATE TABLE eleves (id INTEGER PRIMARY KEY, nom TEXT NOT NULL)"
)
connexion.executemany(
"INSERT INTO eleves (nom) VALUES (?)",
[("Amina",), ("Joël",), ("D'Angelo",)]
)
nom = input("Nom exact à rechercher : ").strip()
if not nom or len(nom) > 100:
print("Le nom doit contenir de 1 à 100 caractères.")
return
lignes = connexion.execute(
"SELECT id, nom FROM eleves WHERE nom = ?", (nom,)
).fetchall()
if not lignes:
print("Aucun élève trouvé.")
for identifiant, valeur in lignes:
print(f"{identifiant} : {valeur}")
finally:
connexion.close()
if __name__ == "__main__":
main()Le point important est (nom,), un tuple d’un élément transmis au pilote avec le marqueur ?. L’apostrophe reste dans la valeur et ne change pas la requête. Le contrôle de longueur est utile, mais ce n’est pas lui qui empêche l’interprétation SQL. Les paramètres représentent des valeurs ; un nom de table ou de colonne dynamique exige une conception adaptée et une liste autorisée, pas la même substitution.
4. XSS : afficher une donnée dans le bon contexte
Une XSS survient lorsqu’un contenu non fiable est traité comme du code actif dans le navigateur. Par exemple, un commentaire mal géré peut devenir une instruction au lieu d’un texte. La défense dépend du contexte de sortie : texte HTML, attribut, URL et JavaScript n’utilisent pas tous le même traitement.
Pour afficher un texte simple, utilisez les mécanismes d’échappement du moteur de gabarits ou une API comme textContent. Évitez de placer directement une chaîne extérieure dans innerHTML. Si l’application autorise du HTML enrichi, utilisez une bibliothèque de nettoyage adaptée et une politique explicite. Une politique de sécurité du contenu peut compléter ces protections, sans remplacer l’encodage correct.
Ne confondez pas validation d’entrée et encodage de sortie. Un nom contenant une apostrophe peut être parfaitement légitime ; le supprimer n’est pas une solution générale. Le programme doit conserver les données utiles et les interpréter correctement dans chaque contexte.
5. Secrets, dépendances et erreurs
Une clé d’API ou un mot de passe ne doit pas être placé dans du JavaScript public ni dans un dépôt accessible aux lecteurs. Un fichier de configuration exclu de Git peut encore être exposé par le serveur : l’exclusion de versionnement n’est pas une règle de contrôle d’accès. Stockez les secrets avec les mécanismes adaptés au déploiement et prévoyez leur rotation en cas d’exposition.
Les bibliothèques constituent une dépendance de sécurité. Inventoriez les versions, suivez les avis pertinents, mettez à jour et vérifiez le fonctionnement. Un rapport automatique nécessite un tri : version concernée, fonction utilisée, possibilité d’exposition et correction. Ne publiez pas les détails internes d’une erreur à l’utilisateur ; conservez une trace utile côté serveur sans y recopier secrets ou données inutiles.
Sur un site statique, un formulaire peut toujours envoyer des données à un service externe et un script tiers peut exécuter du code dans le navigateur. L’absence de base de données locale ne supprime donc pas les questions de confiance, de dépendances et de protection des données.
Exercices et corrigés
Essayez de répondre avant de déplier les corrigés. Les situations et données sont fictives.
1. Tester une autorisation
Vous connaissez un identifiant de dossier difficile à deviner. Pourquoi faut-il quand même contrôler les droits ?
Voir le corrigéMasquer le corrigé
La confidentialité de l’identifiant peut disparaître. L’application doit vérifier que le compte peut effectuer l’action sur ce dossier ; un identifiant imprévisible n’est pas une permission.
2. Expliquer le programme
Quel mécanisme permet au nom D’Angelo de rester une donnée ?
Voir le corrigéMasquer le corrigé
La requête paramétrée, qui transmet le nom séparément de l’instruction SQL. La présence de l’apostrophe n’a pas à être interdite ; la valeur ne devient pas du code SQL.
3. Choisir une sortie HTML
Un commentaire doit être affiché comme texte. Quel est le risque d’un innerHTML direct ?
Voir le corrigéMasquer le corrigé
Le contenu peut être interprété comme du balisage et du code actif. Une sortie texte, par exemple textContent ou un gabarit avec échappement adapté, conserve le commentaire comme donnée.
Sources officielles et approfondissements
Repères consultés le 14 octobre 2026. Les cas GeniusCampus et les schémas sont des exemples pédagogiques originaux.
- OWASP : Top 10, édition 2025
- OWASP : Prévenir les injections SQL
- OWASP : Prévenir les XSS
- Python : sqlite3
Pour pratiquer sur PandaCodeur
Laboratoire 7 : Corriger une injection SQL et traiter une sortie HTML
Objectif : Comparer une cause de vulnérabilité, un correctif et un test de non-régression sur des données locales. Durée indicative : 60 minutes.
L’atelier SQL utilise uniquement une base SQLite en mémoire, avec les dossiers fictifs d’Amina et de Boris. L’anti-exemple concatène une saisie au texte d’une requête. La version corrigée transmet cette saisie comme une valeur de paramètre : elle ne modifie plus la structure SQL.
Ce correctif traite l’interprétation des entrées ; il ne décide pas automatiquement du droit de lire les lignes. Le programme montre donc aussi un filtre de propriétaire issu d’une identité de session simulée. Autorisation et paramétrage sont deux contrôles distincts.
Manipulations guidées
- Exécuter sql et comparer les résultats. L’anti-exemple retourne deux lignes avec la saisie de démonstration ; la requête paramétrée en retourne zéro, car aucun propriétaire ne porte exactement ce nom.
- Vérifier que la recherche normale d’amina retourne toujours 101. Un correctif qui bloque toutes les recherches n’est pas un résultat satisfaisant.
- Vérifier le dernier test : la lecture du dossier 202 avec l’identité de session amina renvoie zéro ligne, même avec une requête syntaxiquement sûre.
- Dans WebGoat local, sélectionner la leçon d’introduction aux injections SQL, puis suivre ses étapes et indices. Documenter la différence entre texte de requête et paramètres, sans appliquer ces essais à une base extérieure.
- Lancer sortie-html. La chaîne <b>Atelier NKILItech</b> est encodée comme du texte. Dans une vue réelle, employer les mécanismes d’échappement du moteur de template ou textContent pour du texte, plutôt que créer du HTML à partir d’une saisie non fiable.
- Rédiger une fiche de correction : cause, emplacement du correctif, test normal, test malveillant local, test d’accès interdit et limite. Pour une URL ou du JavaScript, ne pas réutiliser aveuglément l’encodage prévu pour du texte HTML.
python atelier.py --atelier sql
python atelier.py --atelier sortie-htmlRésultats attendus et preuves à conserver
SQL : anti_exemple_lignes=2, requete_parametree_lignes=0, recherche_normale=[101], acces_autrui_lignes=0. HTML : les chevrons sont représentés par des entités ; aucune page contenant une saisie exécutable n’est ouverte par le programme.
Limites de la démonstration
Les paramètres SQL représentent des valeurs ; ils ne permettent pas de choisir librement un nom de table ou une clause de tri. Les choix structurels demandent une liste de valeurs autorisées. Le petit programme ne remplace pas les essais de l’application complète.
Télécharger les ateliers Python complets, le journal fictif et le modèle de rapport · Mode d’emploi et code complet
Trois exercices d’application corrigés
1. Tester le bon correctif
Pourquoi remplacer les apostrophes par une chaîne vide n’est-il pas notre solution ?
Voir le corrigé 1
Cela altère les données légitimes et ne garantit pas une séparation fiable entre code et valeurs pour tous les contextes. La requête paramétrée conserve la valeur comme donnée, avec le mécanisme du pilote SQL.
2. Conserver la confidentialité
La requête est paramétrée mais renvoie tous les dossiers à tout utilisateur connecté. Est-elle sûre ?
Voir le corrigé 2
Elle peut résister à cette injection tout en violant le contrôle d’accès. Il faut restreindre les lignes selon l’identité et la politique d’autorisation, puis tester les refus entre Amina et Boris.
3. Choisir le contexte
html.escape suffit-il à rendre une chaîne sûre dans tous les endroits d’une page ?
Voir le corrigé 3
Non. L’exercice concerne un contenu textuel HTML. Les URL, scripts et autres contextes ont des contraintes différentes ; mieux vaut éviter les insertions sensibles et utiliser les API ou moteurs adaptés au contexte.
Références du laboratoire
Complément original PandaCodeur, cas NKILItech fictif. Les interfaces de WebGoat peuvent évoluer : relever la version et le titre de la leçon suivie.