Le dossier 1041 et le dossier 1042
Une agence de voyages met les dossiers de ses clients sur son site. Une cliente ouvre le sien : l'adresse se termine par 1041. Par curiosité, elle remplace 1041 par 1042.
La page affiche le dossier d'un inconnu : son nom, son voyage, son adresse. Rien n'a été forcé. Le site n'a simplement jamais demandé à qui appartenait ce dossier.
La règle unique
Attention
Ce laboratoire est une boutique volontairement fragile. Attaquez votre copie privée, et rien d'autre : elle n'a aucune sortie vers Internet. Attaquer un système qui n'est pas le vôtre, ou sans permission de test, est un délit dans presque tous les pays.
À la fin de cette leçon
Remarque
Je peux dire si une requête aurait dû être autorisée.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Authentification | prouver qui l'on est | un mot de passe |
| Autorisation | vérifier ce que l'on a le droit de faire | |
| Rôle | un ensemble de droits qui porte un nom | admin |
| Identifiant | un numéro ou un nom qui désigne une seule fiche | dossier 17 |
| Jeton | une valeur signée que le navigateur envoie pour montrer qu'il est connecté | |
| Code d'état | un nombre au début d'une réponse qui dit comment cela s'est passé | 401 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Être connecté n'est pas être autorisé
Un site pose deux questions. La première est l'authentification : qui êtes-vous ? La seconde est l'autorisation : avez-vous le droit de faire cela ?
Beaucoup de sites fragiles posent la première et oublient la seconde. Ils savent que vous êtes client, alors ils montrent tout ce que vous demandez, même les fiches des autres.
Un code d'état dit comment cela s'est passé
Chaque réponse commence par un code d'état. 200 veut dire : voici. 401 veut dire : le site ne sait pas qui vous êtes. 403 veut dire : il le sait, et la réponse est non.
Les trois commandes suivantes demandent trois choses à la boutique de votre laboratoire, sans vous connecter. Regardez lesquelles elle donne.
Une page pour tous : un produit
curl -s -o /dev/null -w "%{http_code}\n" http://juice-shop:3000/api/Products/1Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Une page pour les connectés : les utilisateurs
curl -s -o /dev/null -w "%{http_code}\n" http://juice-shop:3000/api/UsersAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Ce que dit la boutique quand elle refuse
curl -s http://juice-shop:3000/rest/basket/1 | grep -o "<title>[^<]*</title>"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple travaillé : lire les trois réponses
| Requête | Code | Ce que cela indique |
|---|---|---|
| /api/Products/1 | 200 | Un produit est public : tout le monde peut le lire |
| /api/Users | 401 | La boutique veut savoir qui demande avant de lister des personnes |
| /rest/basket/1 | 401 | Un panier est privé : la boutique veut d'abord un jeton |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un numéro dans l'adresse se change
Les dossiers, paniers et factures portent un numéro. Ce numéro figure souvent dans l'adresse, et chacun peut le modifier.
Le site doit donc vérifier, à chaque requête, que ce compte possède la fiche ou qu'il a un rôle qui peut la lire. Un numéro difficile à deviner n'est pas un contrôle.
Exemple travaillé : un court journal
| Utilisateur | Rôle | Requête | Autorisée ? |
|---|---|---|---|
| lea | client | GET /dossiers/17 (le sien) | Oui, il lui appartient |
| lea | client | GET /dossiers/18 (celui de Hugo) | Non, il n'est pas à elle |
| sam | conseiller | GET /dossiers/18 | Oui, un conseiller lit tous les dossiers |
| hugo | client | GET /admin/comptes | Non, réservé aux administrateurs |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur fréquente
Attention
Beaucoup pensent que cacher un bouton ou un lien protège une page. C'est faux : un navigateur peut demander n'importe quelle adresse, qu'un lien y mène ou non. Le contrôle doit se faire dans le code du serveur qui répond. Cachez aussi le lien, mais ne comptez jamais dessus.
Le serveur contrôle chaque requête
Un traitement sûr fait trois choses dans l'ordre. Il trouve qui demande. Il charge la fiche. Il vérifie le propriétaire ou le rôle, et refuse si aucun ne convient.
On refuse avec 403. Le contrôle est fait dans le serveur, à un seul endroit, pour qu'aucune page ne l'oublie.
Un contrôle propriétaire ou conseiller
def peut_lire(utilisateur, role, proprietaire):
if role == "conseiller":
return True
return utilisateur == proprietaire
# Changez les noms et lancez le code. Puis ajoutez le rôle "admin".
print(peut_lire("lea", "client", "lea"))
print(peut_lire("lea", "client", "hugo"))
print(peut_lire("sam", "conseiller", "hugo"))