ParcoursOuvrir l'appli

Les failles des sites web

Sécurité et hacking éthique · 55 min

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
< &lt; pour que <script> ne soit plus une balise
> &gt; idem
& &amp; le caractère de base des entités
" &quot; pour ne pas sortir d'un attribut

Après échappement, <script> devient le texte &lt;script&gt;, 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 :

  1. & par &amp; (en premier, sinon on ré-échapperait les suivants) ;
  2. < par &lt; ;
  3. > par &gt; ;
  4. " par &quot;.
Voir une solution
def echapper(texte):
    """Rend un texte sûr à insérer dans une page HTML."""
    texte = texte.replace("&", "&amp;")
    texte = texte.replace("<", "&lt;")
    texte = texte.replace(">", "&gt;")
    texte = texte.replace('"', "&quot;")
    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