Les failles des sites web
La règle unique de la sécurité web
Presque toutes les failles web viennent de la même erreur : faire confiance à ce que l'utilisateur envoie. L'injection SQL du module précédent en était un exemple. En voici d'autres, parmi les plus répandues.
Le XSS : injecter du code dans une page
Imagine un site de commentaires. Tu écris comme commentaire :
<script>vole_les_cookies()</script>
Si le site réaffiche ton commentaire tel quel dans la page, ce <script> s'exécute dans le navigateur de chaque personne qui lit les commentaires. C'est le XSS stocké, le plus dangereux : l'attaque touche tous les visiteurs.
La défense : échapper le HTML
La parade est de transformer les caractères spéciaux du HTML en entités inoffensives avant d'afficher du texte venu de l'utilisateur :
| Caractère | Devient | Pourquoi |
|---|---|---|
< |
< |
pour que <script> ne soit plus une balise |
> |
> |
idem |
& |
& |
le caractère de base des entités |
" |
" |
pour ne pas sortir d'un attribut |
Après échappement, <script> devient le texte <script>, qui s'affiche à l'écran mais ne s'exécute pas. En Python, la bibliothèque standard html fait ça avec html.escape, mais tu vas l'écrire à la main pour comprendre.
Exercice : Neutraliser une attaque XSS
Écris echapper(texte) qui rend un texte sûr à afficher dans une page, en remplaçant, dans cet ordre :
&par&(en premier, sinon on ré-échapperait les suivants) ;<par<;>par>;"par".
Voir une solution
def echapper(texte):
"""Rend un texte sûr à insérer dans une page HTML."""
texte = texte.replace("&", "&")
texte = texte.replace("<", "<")
texte = texte.replace(">", ">")
texte = texte.replace('"', """)
return texte
attaque = '<script>alert("vole")</script>'
print(echapper(attaque))Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice
Deux autres failles classiques
Exercice : Repérer une faille d'accès (IDOR)
Un serveur gère des factures. Chaque facture appartient à un utilisateur. Écris voir_facture(factures, demandeur, id_demande) qui :
- renvoie le montant de la facture si elle appartient bien au
demandeur; - renvoie
"Accès refusé"si la facture appartient à quelqu'un d'autre (la faille IDOR qu'il faut empêcher) ; - renvoie
"Introuvable"si l'id n'existe pas.
C'est le contrôle que le site vulnérable avait oublié.
Voir une solution
factures = {
1043: {"proprietaire": "awa", "montant": 15000},
1044: {"proprietaire": "paul", "montant": 80000},
1045: {"proprietaire": "awa", "montant": 4500},
}
def voir_facture(factures, demandeur, id_demande):
"""Renvoie le montant seulement si la facture appartient au demandeur."""
if id_demande not in factures:
return "Introuvable"
if factures[id_demande]["proprietaire"] != demandeur:
return "Accès refusé"
return factures[id_demande]["montant"]
print(voir_facture(factures, "awa", 1043))
print(voir_facture(factures, "awa", 1044))
print(voir_facture(factures, "awa", 9999))Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice