Examen de spécialiste agréé en sécurité de l'information — Printemps 2024 (Reiwa 6), question 1 de l'après-midi expliquée — JWT alg=none, autorisation API et mesure provisoire par WAF
· Mis à jour le: · Go Komura · Spécialiste agréé en sécurité de l'information, Examen RISS, API, Sécurité des API, JWT, Authentification, Autorisation, WAF, Log4Shell, Sécurité de l'information, Vulnérabilité, IPA
Historique des révisions (première version, publiée le 6 Aug 2026)
- Première publication
Citer cet article(DOI (archive enregistrée): 10.5281/zenodo.22175996)
Les DOI ci-dessous renvoient à des versions déjà archivées et peuvent différer du texte actuel. Pour citer le texte actuel, utilisez l’URL de cette page.
Go Komura (2026). Examen de spécialiste agréé en sécurité de l'information — Printemps 2024 (Reiwa 6), question 1 de l'après-midi expliquée — JWT alg=none, autorisation API et mesure provisoire par WAF. KomuraSoft LLC. https://comcomponent.com/fr/blog/sc-exam-r6s-pm-q1-api-security/
- DOI (archive enregistrée)
- 10.5281/zenodo.22175996
- DOI (dernière version enregistrée)
- 10.5281/zenodo.22175997
« On vérifie le JWT, et pourtant on peut usurper l’identité d’autrui. » « On a un JWT parfaitement valide, et pourtant on peut lire les informations de quelqu’un d’autre. » Les deux se ressemblent, mais on ne les corrige pas au même endroit. Le premier est un problème de validation du jeton ; le second, un problème d’autorisation sur les données cibles.
La question 1 de l’après-midi de l’examen de spécialiste agréé en sécurité de l’information, session printemps 2024 (Reiwa 6), prend pour sujet une API appelée depuis un smartphone et demande de démêler ces vérifications distinctes. La première moitié traite du JWT, de l’identifiant d’utilisateur, des champs de mise à jour et du code d’authentification ; la seconde, d’une vulnérabilité de bibliothèque et d’un WAF.1
Cet article s’appuie sur les exemples de réponses officiels et le commentaire de notation, et explique chaque point dans l’ordre « l’essentiel de la réponse → le fondement dans l’énoncé → la conception à ajouter en pratique ». Lisez-le en séparant ce qu’il faut écrire dans la limite de caractères de l’examen et ce dont un système réel a besoin.23
1. D’abord la conclusion — réussir une validation ne permet pas d’omettre la suivante
Le principe qui traverse cet article est le suivant : ne jamais prendre le succès de la validation précédente comme raison d’omettre la frontière de confiance suivante. Une frontière de confiance est la ligne qui décide à quelles conditions une valeur arrivée de l’extérieur peut être crue.
Détenir un JWT valide ne signifie pas que l’on a le droit de lire les informations d’autrui. Pouvoir mettre à jour ses propres informations ne signifie pas que l’on a le droit de modifier aussi l’état de facturation. La date d’expiration du code d’authentification et le WAF exigent chacun leurs propres contrôles et pratiques d’exploitation.
Plan des réponses
Le tableau suivant reprend l’essentiel des réponses officielles. Pour les réponses rédigées, vérifiez dans chaque chapitre la limite de caractères de la question et le fondement.2
| Question et blanc | Essentiel de la réponse | Explication détaillée |
|---|---|---|
| Question 1, blanc a | Sans état (stateless) | Chapitre 3 |
| Question 2(1), blanc b | 500 secondes | Chapitre 4 |
| Question 2(2) | Vérifier que le alg de l’en-tête JWT n’est pas NONE | Chapitre 5 |
| Question 2(3) | Vérifier que l’identifiant d’utilisateur du JWT correspond au mid | Chapitre 6 |
| Question 2(4), blanc c | Module commun P | Chapitre 7 |
| Question 2(5), blanc d | Verrouiller le compte lorsque le nombre d’échecs consécutifs dépasse le seuil | Chapitre 8 |
| Question 3(1) | Enregistrer et vérifier les accès à index.html sur le serveur de test | Chapitre 9 |
| Question 3(2), blancs e et f | Header dans les deux cas | Section 10.1 |
| Question 3(3) | Une expression régulière qui gère majuscules et minuscules | Section 10.2 |
| Question 3(4) | Empêcher un blocage par faux positif et examiner les alertes | Section 10.3 |
Commencez par le chapitre 2 pour saisir la structure du problème, puis lisez les chapitres 3 à 10 dans l’ordre des questions pour suivre l’ensemble. La façon de rédiger les réponses est au chapitre 12, et la checklist à utiliser pour la conception et la revue de code en pratique au chapitre 13.
Dans le diagramme, un trait continu marque une relation qui vaut toujours et un trait pointillé une relation conditionnelle (les conditions figurent dans l’explication de chaque relation sur la page de détail). La liste complète des relations (18 au total, avec preuve et niveau de certitude) et les définitions des concepts principaux sont rassemblées sur la page de détail de la carte des connaissances (en japonais). Données : JSON-LD / Turtle
2. Structure du problème — lire cinq vérifications séparément
Le décor du problème est la société G, qui s’apprête à lancer un service de santé. Les utilisateurs saisissent repas, poids, etc. depuis une application smartphone, et reçoivent une évaluation des risques pour la santé ainsi que des conseils de menus. Le système est construit dans le cloud, en combinant une passerelle API, un traitement événementiel et une base de données managée.
Les noms de produits et de services de l’énoncé sont abstraits. Cet article ne reproduit pas tels quels les schémas du livret ; il reformule la structure nécessaire pour comprendre les questions. Les passages qui donnent l’essentiel de la réponse officielle et les compléments pratiques sont distingués.1
flowchart TB
accTitle: Vue d'ensemble du problème
accDescr: Lire le code d'authentification, le JWT, l'identifiant cible, les champs de mise à jour et l'exécution depuis une entrée externe comme autant de vérifications distinctes.
A["Requête de l'utilisateur"] --> B["Contrôle du code d'authentification"]
B --> C["Émission et validation du JWT"]
C --> D["API utilisateur"]
D --> E["Autorisation du mid cible"]
D --> F["Autorisation du status de mise à jour"]
D -.-> G["Enregistrement d'une entrée externe dans le journal"]
G --> H["Bibliothèque vulnérable"]
H --> I["Exécution de code externe via JNDI"]
Figure 1 : De l’authentification aux opérations d’API et au traitement des journaux, il n’y a pas un seul endroit où l’on fait confiance à une valeur.
2.1. Séparer authentification, validation du jeton et deux types d’autorisation
Après avoir confirmé l’identité par le code d’authentification, puis émis et validé le JWT, il reste l’autorisation sur les données et sur les champs. Sur le chemin qui envoie une entrée externe vers le journal, il faut aussi une frontière qui empêche de traiter cette entrée comme une instruction.
[Identifiant d'utilisateur et mot de passe]
|
v
[Vérification du code à 4 chiffres] ---- sans limite de tentatives ----> force brute
|
v
[Émission du JWT]
|
v
[Bibliothèque JWT] ------- autorise alg=none ------> falsification de l'identifiant
|
v
[API utilisateur]
| |
| +-- transmet status tel quel ----> faille d'autorisation au niveau propriété
|
+-- fait confiance au mid -----------------------> faille d'autorisation au niveau objet
[Enregistrement d'une entrée externe dans le journal]
|
v
[Bibliothèque vulnérable] ---- JNDI/LDAP/HTTP ------> exécution de code externe
Ce qui compte le plus ici, c’est la distinction suivante.
| Vérification | Question posée | Exemple de rupture dans ce problème |
|---|---|---|
| Authentification | Qui êtes-vous ? | Force brute du code à 4 chiffres |
| Validation du jeton | Cette identité a-t-elle été falsifiée ? | alg=none |
| Autorisation au niveau de l’objet | A-t-on le droit d’accéder aux données de cet utilisateur ? | Substitution de mid |
| Autorisation au niveau de la propriété | A-t-on le droit de modifier ce champ ? | status=paid |
| Frontière entre entrée et exécution | Une entrée externe est-elle interprétée comme une instruction ? | JNDI Lookup |
Le succès de la vérification précédente n’est pas une raison d’omettre la suivante. Même un utilisateur qui détient un JWT valide n’a pas forcément le droit de lire les données d’autrui. Même un utilisateur qui peut mettre à jour ses propres données n’a pas forcément le droit de modifier aussi l’état de facturation.
Une fois cette séparation en étapes maîtrisée, les réponses de chaque question cessent d’être de la mémorisation.
flowchart TB
accTitle: Différence entre authentification et autorisation
accDescr: Confirmer le sujet ne dispense pas de vérifier séparément s'il a le droit d'opérer sur les données et les champs cibles.
A["Authentification et validation du jeton"] --> B["Déterminer de qui vient la requête"]
B --> C["A-t-on le droit d'atteindre ces données ?"]
C --> D["A-t-on le droit de modifier ce champ ?"]
Figure 2 : Différence entre authentification et autorisation. L’authentification vient d’abord ; l’autorisation est une autre vérification.
2.2. Distinguer la question 2 par les valeurs que l’attaquant a changées
Les points faciles à confondre dans la question 2 se classent par la valeur que l’attaquant a contrôlée.
| Attaque | Valeur changée par l’attaquant | Endroit auquel il ne fallait pas faire confiance | Contre-mesure de fond |
|---|---|---|---|
| Falsification du JWT | alg de l’en-tête JWT, identifiant d’utilisateur de la charge utile |
L’algorithme de validation déclaré par le jeton lui-même | Fixer les algorithmes autorisés côté serveur |
| Obtention des informations d’autrui | mid de la requête |
L’identifiant cible spécifié par le client | Le recouper avec le sujet du JWT, ou le déterminer à partir du JWT |
| Passage en utilisateur payant | status hors spécification |
Toutes les propriétés liées automatiquement | Mettre les propriétés modifiables en liste d’autorisation |
| Contournement du code à 4 chiffres | Candidats otp |
Tentatives d’authentification illimitées | Introduire une limite d’échecs, un délai et une évaluation du risque |
L’important est de ne pas tout regrouper sous « valider les valeurs d’entrée ».
algest une politique de traitement cryptographiquemidest une autorisation au niveau de l’objetstatusest une autorisation au niveau de la propriétéotpest la résistance à la devinette en ligne
Même à l’intérieur d’une seule requête HTTP, les raisons de les protéger diffèrent.
3. Question 1 — même sans état, on conserve les données métier et le compteur d’échecs
La question 1 porte sur l’un des principes de conception des API RESTful : la propriété de ne pas gérer de session.
Réponse : le blanc a est « sans état » (stateless).2
3.1. Fondement — chaque requête contient à elle seule les informations nécessaires au traitement
Sans état signifie que, même si le serveur ne se souvient pas de l’état de conversation de la requête précédente, chaque requête contient à elle seule les informations nécessaires au traitement. Dans ce problème, l’application smartphone joint un JWT à l’en-tête Authorization à chaque requête. Le serveur valide ce JWT et identifie l’utilisateur de cette requête.
3.2. Point facile à mal lire — on ne jette pas pour autant les données ni le compteur d’échecs
L’erreur fréquente est de lire « sans état » comme « le serveur ne détient aucun état ». En réalité, on conserve normalement les états suivants.
- La base de données qui stocke les informations utilisateur et les données de santé
- L’état de facturation
- La valeur du code d’authentification, sa date d’expiration et le nombre d’échecs
- La clé de signature du JWT
- Les informations de révocation, si la conception utilise une liste de révocation
- Les journaux et les enregistrements d’audit
Ce que l’on ne détient pas, c’est un état de session côté serveur destiné uniquement à poursuivre la conversation, pris comme prérequis de chaque appel d’API.
De plus, être sans état n’améliore pas automatiquement la sécurité. Envoyer un JWT à chaque fois facilite la répartition horizontale, mais si la validation du JWT est erronée, l’erreur se propage uniformément à tous les nœuds. Une propriété d’architecture et la correction en matière de sécurité sont deux choses distinctes.
flowchart TB
accTitle: Sans état et états conservés
accDescr: Traiter chaque requête sans dépendre de l'historique de conversation n'empêche pas de conserver des états tels que les données métier et le compteur d'échecs.
A["Requête avec JWT"] --> B["Identifier l'utilisateur à partir de cette seule requête"]
B --> C["Exécuter le traitement et répondre"]
D["Informations utilisateur, facturation, nombre d'échecs"] -.-> C
C -.-> E["Aucune dépendance à la conversation précédente"]
Figure 3 : Supprimer la dépendance à la conversation et conserver les états métier et de sécurité sont compatibles.
4. Question 2(1) — calculer le temps moyen de percée du code à 4 chiffres
Réponse : le blanc b est « 500 ». L’unité est la seconde.2
4.1. Fondement — aligner le nombre de candidats, la vitesse de tentative et la durée de validité
L’API d’authentification, si l’identifiant d’utilisateur et le mot de passe correspondent, envoie un nombre à 4 chiffres par e-mail. Ensuite, si l’identifiant et le code à 4 chiffres correspondent, elle émet un JWT. Le code est valide pendant 10 minutes à compter de sa génération.
Lors du diagnostic, 10 tentatives par seconde étaient possibles. Il faut calculer en combien de secondes, en moyenne, on percera.
Le calcul utilise « la moitié du nombre de candidats »
Les nombres à 4 chiffres, zéro en tête compris, forment les 10 000 combinaisons suivantes.
0000, 0001, 0002, ... , 9999
Lorsque la bonne réponse est choisie uniformément et que l’on essaie sans doublon dans l’ordre, l’examen calcule le nombre moyen de tentatives comme la moitié du nombre de candidats.
nombre moyen de tentatives = 10 000 ÷ 2 = 5 000 tentatives
temps moyen = 5 000 ÷ 10 tentatives/s = 500 secondes
Cette approximation donne les 500 secondes de la réponse officielle. En moyenne stricte de la 1re à la 10 000e tentative, on obtient 5 000,5 tentatives, mais on s’aligne ici sur la réponse de l’examen.
Le maximum prend 1 000 secondes, mais le problème demande la moyenne. Or la durée de validité du code est de 600 secondes, donc plus longue que les 500 secondes du temps moyen de percée. C’est la raison pour laquelle on a jugé que « la percée est probable ».
flowchart TB
accTitle: Ordre de grandeur temporel du code d'authentification à 4 chiffres
accDescr: Dans l'approximation de l'examen, la moyenne est 500 secondes ; sans doublon, 60 pour cent des candidats tiennent dans les 600 secondes de validité.
A["10 000 candidats"] --> B["Moyenne d'environ 5 000 tentatives"]
B --> C["À 10 par seconde, environ 500 secondes"]
C --> D["Plus court que les 600 secondes de validité"]
D -.-> E["6 000 candidats vérifiés en 600 secondes"]
Figure 4 : Ordre de grandeur temporel du code à 4 chiffres. En essayant en moyenne la moitié des candidats, on tombe juste pendant la durée de validité.
4.2. Complément pratique — regarder le nombre de tentatives possibles, pas seulement le délai d’expiration
La force d’un code d’authentification ne se décide ni par le nombre de chiffres seul, ni par la durée de validité seule.
nombre de tentatives possibles pendant la validité
= tentatives par seconde × durée de validité
= 10 × 600
= 6 000 tentatives
En essayant des valeurs non répétées dans l’ordre, on peut vérifier 60 % des 10 000 combinaisons pendant la durée de validité. Même avec un délai d’expiration, l’absence de limite sur le nombre de tentatives ne suffit pas.
Le NIST SP 800-63B en vigueur exige au moins 6 chiffres pour un secret de courte durée utilisé en authentification hors bande, et rend obligatoire une limite de tentatives en dessous de 64 bits. Il demande aussi de ne pas utiliser le courrier électronique comme authentification hors bande4. À l’examen, on répond dans le cadre donné — 4 chiffres et envoi par e-mail — mais, pour une conception nouvelle en pratique, ces prémisses elles-mêmes devraient être réexaminées.
5. Question 2(2) — ne pas laisser l’attaquant choisir la méthode de validation du JWT
Essentiel de la réponse
La question demande, en 20 caractères ou moins chacun, « sur quelles données, et quelle validation, la bibliothèque Q corrigée effectue ».
L’exemple de réponse est le suivant.
| Élément | Essentiel de la réponse |
|---|---|
| Données cibles de la validation | La valeur indiquée dans alg de l’en-tête JWT |
| Contenu de la validation | Vérifier qu’elle n’est pas NONE |
C’est la correction directe de la vulnérabilité de l’énoncé.2 Répondre seulement « valider la signature » reviendrait à répéter un traitement déjà implémenté. Le commentaire de notation signale précisément ce type d’erreur.3
5.1. Fondement — c’est le « choix » de la validation de signature déjà présente qui est faux
Le JWT du problème se compose de trois parties : en-tête, charge utile et signature.
base64url(header).base64url(payload).base64url(signature)
L’en-tête enregistrait RS256 comme algorithme de signature. La charge utile contient l’identifiant d’utilisateur, l’heure d’émission et la date d’expiration.
Le diagnostiqueur a modifié les deux points suivants.
- Changer le
algde l’en-tête deRS256enNONE - Changer l’identifiant d’utilisateur de la charge utile vers un autre utilisateur
En envoyant ce JWT, la validation réussissait et l’on pouvait usurper l’identité d’autrui.
flowchart TB
accTitle: Déroulement de l'attaque JWT alg=none
accDescr: Si l'attaquant change la méthode de validation et l'identifiant, une bibliothèque qui autorise none accepte le JWT falsifié.
A["Obtenir un JWT valide"] --> B["Changer alg en none"]
B --> C["Changer user vers un autre utilisateur"]
C --> D["La bibliothèque omet la validation de signature"]
D --> E["Accepter comme un autre utilisateur"]
Figure 5 : Déroulement de l’attaque JWT alg=none. C’est l’attaquant qui choisit l’algorithme de validation.
none n’est pas une valeur absente de la spécification
RFC 7519 définit le « Unsecured JWT » dont alg vaut none, c’est-à-dire un JWT sans signature ni chiffrement5. La valeur none n’est donc pas inexistante dans la spécification.
Le problème est qu’une API qui ne devrait accepter que des JWT signés a accepté le none spécifié par l’attaquant.
Le traitement vulnérable, écrit conceptuellement, ressemble à ceci.
1. Lire l'en-tête JWT
2. Choisir la méthode de validation d'après le alg écrit dans l'en-tête
3. Si alg vaut none, ne pas valider la signature
4. Faire confiance à l'identifiant d'utilisateur de la charge utile
On laisse une entrée contrôlée par l’attaquant choisir la force même de la sécurité.
5.2. Complément pratique — fixer les algorithmes autorisés côté serveur
Ici, il faut séparer la réponse de l’examen et la recommandation pratique.
RFC 8725 exige que la bibliothèque JWT fasse spécifier par l’appelant l’ensemble des algorithmes autorisés, et n’en utilise aucun en dehors de cet ensemble6. Autrement dit :
mauvaise idée :
accepter si token.header.alg != "none"
bonne idée :
n'accepter que si l'algorithme est dans serverConfig.allowedAlgorithms
exemple : allowedAlgorithms = ["RS256"]
Même en rejetant seulement none, il peut rester un algorithme faible, ou une confusion d’algorithmes qui mélange clé publique et clé secrète. Le principe est de fixer étroitement les conditions d’acceptation, plutôt que d’allonger des conditions négatives.
Pour valider un JWT, on vérifie au moins, selon l’usage, les points suivants en plus de l’algorithme.
| Élément | Ce qu’il faut confirmer |
|---|---|
| Signature | Peut-on valider avec la clé et l’algorithme prévus ? |
iss |
L’émetteur est-il de confiance ? |
aud |
Le jeton a-t-il été émis pour cette API ? |
exp |
Est-il encore dans sa période de validité ? |
nbf |
N’est-on pas avant l’heure de début d’utilisation ? |
sub ou identifiant d’utilisateur |
S’agit-il d’un sujet valide pour l’application ? |
| Type de jeton | N’a-t-on pas confondu jeton d’identité et jeton d’accès, etc. ? |
Dans ce problème, la clé de la charge utile s’appelle user ; en pratique, on utilise le sub standard, ou l’on définit clairement le sens d’une revendication propriétaire.
flowchart TB
accTitle: Validation JWT sûre et validation JWT dangereuse
accDescr: Ne pas décider de la méthode de validation d'après la déclaration du jeton ; valider la signature et les revendications seulement après les conditions autorisées côté serveur.
A["Réception du JWT"] --> B{"Algorithme autorisé par le serveur ?"}
B -->|"non"| X["Refuser"]
B -->|"oui"| C["Valider la signature et chaque revendication"]
C --> D["Traiter comme un sujet validé"]
Y["Traitement dangereux"] -.-> Z["Omettre la validation à cause du none déclaré"]
Figure 6 : Validation sûre et validation dangereuse. En pratique, on fixe étroitement les algorithmes autorisés.
5.3. Séparer signature et confidentialité — base64url n’est pas un chiffrement
Autre malentendu fréquent avec JWT : l’en-tête et la charge utile sont exprimés en base64url, mais ce n’est pas un chiffrement. Quiconque peut les décoder et les lire.
La signature garantit seulement que, si la validation réussit, le contenu n’a pas été falsifié après l’émission. Cela ne signifie pas que l’on a le droit de mettre des informations personnelles confidentielles dans la charge utile d’un JWT signé.
flowchart TB
accTitle: Signature JWT et confidentialité sont distinctes
accDescr: base64url est une représentation lisible par un tiers ; la détection de falsification par signature et la confidentialité se pensent séparément.
A["JWT signé"] --> B["Lire l'en-tête et la charge utile"]
B --> C["Décoder le base64url"]
C --> D["Le contenu n'est pas secret"]
A --> E["Valider correctement la signature"]
E --> F["Vérifier l'absence de falsification"]
Figure 7 : La signature sert à détecter une falsification ; ce n’est pas une fonction qui cache le contenu.
6. Question 2(3) — un JWT valide et une cible d’opération valide sont deux choses distinctes
Essentiel de la réponse
Le soulignement ② du tableau 5 demande, en 40 caractères ou moins, le traitement à ajouter au traitement d’appel du module commun P.
L’exemple de réponse est le suivant.2
Un traitement qui vérifie si l’identifiant d’utilisateur contenu dans le JWT correspond à la valeur de mid
La destination d’ajout indiquée par la question n’est pas le module commun P lui-même, mais le « traitement d’appel de P » qui appelle P. C’est là que l’on ajoute la confirmation de correspondance entre JWT et mid.1
En pratique, l’objectif, y compris du côté de P, est de mener l’autorisation de façon cohérente dans la couche commune par laquelle on atteint les données. GET et PUT, ainsi que d’autres API qui utiliseront P plus tard, bénéficient plus facilement de la même autorisation. Se contenter de copier la comparaison dans chaque écran ou point de terminaison produit des oublis d’implémentation.
6.1. Fondement — le sujet du JWT et le mid cible de l’opération sont passés séparément
Ici, l’attaque ne falsifie pas le JWT lui-même.
L’API utilisateur reçoit un identifiant d’utilisateur mid en GET ou PUT. Le module commun P récupère et met à jour, dans la base, les informations utilisateur liées à ce mid.
Le schéma de l’attaque est simple.
identifiant du JWT : user01 ← JWT correctement signé
mid de la requête : user02 ← modifié par l'attaquant
La signature du JWT est correcte, donc l’authentification réussit. Mais l’API fait confiance tel quel à mid=user02 et renvoie les informations de user02.
C’est le cas typique de ce que l’OWASP API Security Top 10 2023 appelle Broken Object Level Authorization (BOLA). Lorsque l’on accède aux données avec un identifiant d’objet spécifié par l’utilisateur, il faut, à chaque fois, confirmer l’autorisation sur cet objet7.
flowchart TB
accTitle: Attaque BOLA
accDescr: Le sujet du JWT valide et le mid de la requête diffèrent, mais on renvoie les informations d'autrui en n'utilisant que le mid.
A["JWT à signature correcte (user01)"] --> C["API utilisateur"]
B["mid modifié (user02)"] --> C
C --> D["Pas de recoupement avec le sujet"]
D --> E["Récupérer et mettre à jour les données de user02"]
Figure 8 : Attaque BOLA. L’authentification passe, mais l’autorisation n’est pas vérifiée.
6.2. Complément pratique — une API dédiée à soi-même ne reçoit pas de mid
Pour une API qui ne récupère et ne met à jour que les informations de l’appelant, il n’est pas nécessaire de recevoir l’identifiant d’utilisateur du client.
GET /users/me
Authorization: Bearer <JWT>
Côté serveur, on extrait le sujet du JWT validé.
principal = validateJwt(request.authorization)
userId = principal.subject
return repository.getUser(userId)
La mise à jour est identique.
principal = validateJwt(request.authorization)
input = validateProfileUpdate(request.body)
repository.updateProfile(
userId = principal.subject,
name = input.name,
age = input.age
)
Une comparaison, si on l’écrit, protège. Mais une conception qui ne reçoit pas l’identifiant cible de l’extérieur réduit d’elle-même la classe de bogues consistant à oublier d’écrire la comparaison.
Si un administrateur doit opérer sur les informations d’un autre utilisateur, on sépare ainsi.
PUT /users/me pour l'utilisateur ordinaire
PUT /admin/users/{userId} pour l'administrateur
Côté administrateur, on exige une autre autorisation, un journal d’audit, et au besoin une réauthentification. La frontière de la politique d’autorisation se voit mieux qu’en « ajoutant une exception administrateur à l’API utilisateur ordinaire ».
flowchart TB
accTitle: Comment empêcher BOLA
accDescr: Vérifier la correspondance entre le sujet validé et le mid, ou, pour une API dédiée à soi-même, dériver la cible du sujet pour réduire les oublis de comparaison.
A["Sujet du JWT validé"] --> B{"Comment décider l'identifiant cible"}
B -->|"on reçoit mid"| C{"Correspond au sujet ?"}
C -->|"oui"| D["Opérer sur ses propres données"]
C -->|"non"| E["Refuser"]
B -->|"API dédiée à soi-même"| F["Dériver l'identifiant cible du sujet"]
F --> D
Figure 9 : Comment empêcher BOLA. Soit on ne reçoit pas de mid, soit on le recoupe avec le sujet du JWT.
6.3. Confirmation — « qui » et « ce que l’on a le droit de faire » sont distincts
À l’examen comme en pratique, les formulations suivantes sont utiles.
- Authentification : qui l’on est
- Autorisation : ce que cette personne a le droit de faire
La réussite de la validation de signature du JWT va jusqu’à « on peut faire confiance au sujet représenté par ce jeton ». « Ce sujet a le droit de lire user02 » doit être confirmé séparément.
7. Question 2(4) — n’accepter que les champs que l’on a le droit de mettre à jour
Réponse : le blanc c est « module commun P ».2
7.1. Fondement — où le status hors spécification a-t-il été transmis ?
La spécification de l’API utilisateur définit les paramètres de mise à jour suivants.
mid identifiant d'utilisateur
name nom
age âge
Pourtant le diagnostiqueur a ajouté la valeur suivante, absente de la spécification.
status=paid
Alors le statut d’un utilisateur gratuit est devenu celui d’un utilisateur payant.
D’après l’énoncé, le service L transmettait tous les paramètres reçus au module commun P, sans les valider. P était conçu pour pouvoir mettre à jour la base tels quels.
On en déduit que la destination capable de recevoir une valeur hors spécification et de mettre à jour jusqu’au statut de l’utilisateur est le module commun P.
flowchart TB
accTitle: Mass Assignment
accDescr: Transmettre jusqu'au status hors spécification au module commun et le mettre à jour permet à l'utilisateur de changer l'état de facturation.
A["La spécification est mid, name, age"] --> B["Ajouter status=paid"]
B --> C["Passer tous les paramètres à P"]
C --> D["Répercuter tels quels dans les données internes"]
D --> E["L'état de facturation devient paid"]
Figure 10 : Mass Assignment. Une propriété hors spécification est répercutée telle quelle dans l’objet interne.
7.2. Différence avec BOLA — protéger non pas la cible, mais un champ à l’intérieur
La substitution de mid du chapitre précédent et l’ajout de status se ressemblent, mais la granularité à protéger diffère.
| Vulnérabilité | Ce que l’attaquant change | Ce qu’il fallait confirmer |
|---|---|---|
Substitution de mid |
L’objet cible | Cet utilisateur a-t-il le droit d’accéder à cet enregistrement utilisateur ? |
Ajout de status |
Une propriété à l’intérieur de l’objet | Cet utilisateur a-t-il le droit de modifier ce champ ? |
L’OWASP API Security Top 10 2023 traite le second comme Broken Object Property Level Authorization, et y range l’ancien Mass Assignment8.
7.3. Complément pratique — faire du type d’entrée de mise à jour une liste d’autorisation
Une implémentation vulnérable ressemble, conceptuellement, à ceci.
entity = repository.find(body.mid)
bindAllProperties(entity, body)
repository.save(entity)
Même si l’écran n’a de champs que pour name et age, l’attaquant peut fabriquer directement une requête HTTP. Un champ absent de l’interface n’est pas une frontière de sécurité.
Une implémentation sûre explicite les champs modifiables.
input = parseExactSchema(body, fields = ["name", "age"])
entity = repository.find(authenticatedUserId)
entity.name = input.name
entity.age = input.age
repository.save(entity)
Deux points comptent ici.
- Ne placer dans le type d’entrée de mise à jour que les champs que l’utilisateur a le droit de changer
- Ne pas ignorer les champs inconnus hors spécification : les refuser de préférence comme une erreur
Ignorer silencieusement un champ inconnu peut masquer l’échec de l’attaque, mais on passe à côté d’une erreur d’implémentation client ou d’un signe d’attaque. Sauf raison de compatibilité, un schéma strict qui refuse facilite l’enquête.
flowchart TB
accTitle: Autorisation au niveau du champ
accDescr: Limiter le type d'entrée de mise à jour à name et age, et mettre à jour l'état de facturation par une voie dédiée à partir d'une notification de paiement validée.
A["Demande de mise à jour du profil"] --> B{"Seulement name et age ?"}
B -->|"oui"| C["Mettre à jour uniquement les champs autorisés"]
B -->|"non"| D["Refuser les champs inconnus"]
E["Notification de paiement validée"] --> F["Recoupement du paymentId et prévention des doublons"]
F --> G["Mettre à jour status par une voie dédiée"]
Figure 11 : Autorisation au niveau du champ. On limite les champs modifiables par une liste d’autorisation, et l’état de facturation se change par une autre voie.
7.4. L’état de facturation ne se change qu’à partir d’un résultat de paiement validé
status=paid ne fait pas partie du profil utilisateur. C’est un état dérivé d’un fait côté serveur : le paiement a réussi.
mise à jour du profil utilisateur
-> seuls name / age sont modifiables
notification validée du service de paiement
-> recouper paymentId
-> empêcher un traitement en double
-> passer status à paid
Même s’il est stocké dans la même colonne de base, le droit de le modifier et la voie pour le faire sont distincts. Utiliser l’entité interne telle quelle comme type d’entrée de l’API externe efface cette frontière.
7.5. Inclure jusqu’à l’autorisation et la restriction d’entrée dans les composants communs
Dans ce problème apparaissent deux composants communs : la bibliothèque de gestion JWT Q et le module commun P.
Les composants communs ont de grands avantages.
- Corriger un seul endroit répercute la correction sur toutes les API qui les utilisent
- On évite de dupliquer l’implémentation de l’autorisation et de la validation dans chaque fonction
- On peut concentrer les cibles de test
- On peut unifier le format des journaux et de l’audit
En contrepartie, une erreur se propage aussi à l’ensemble.
- Si la bibliothèque Q accepte
alg=none, toutes les API qui utilisent JWT deviennent dangereuses - Si le module commun P accepte un
midou unstatusquelconque, GET et PUT deviennent tous deux dangereux - Si la bibliothèque vulnérable H est utilisée en socle, plusieurs chemins qui journalisent des en-têtes HTTP deviennent une surface d’attaque
Donc ce qu’il faut factoriser n’est pas le simple accès aux données. Il faut factoriser les invariants de sécurité, et tester sévèrement ces composants communs à eux seuls.
Par exemple, on fixe le contrat de P ainsi.
P.getOwnUser(authenticatedSubject)
P.updateOwnProfile(authenticatedSubject, ProfileUpdate{name, age})
Il est plus sûr de ne pas exposer telles quelles, à un appelant ordinaire, des API de bas niveau comme les suivantes.
P.getUser(arbitraryMid)
P.updateUser(arbitraryMap)
Les secondes ne sont nécessaires que sur des voies limitées, comme le traitement d’administration. Distribuer la liberté de bas niveau à toutes les API, c’est concevoir en espérant que chaque appelant s’en servira correctement à chaque fois.
flowchart TB
accTitle: Rétrécir le contrat des composants communs
accDescr: Inclure l'autorisation et le type d'entrée dans le contrat du composant commun réduit la dépendance au fait que chaque appelant s'en serve correctement.
A["API pour l'utilisateur ordinaire"] --> B["Sujet validé et DTO de mise à jour"]
B --> C["Unifier l'autorisation dans le composant commun"]
C --> D["Opérer sur les données autorisées"]
E["Opération sur un ID quelconque et une Map quelconque"] -.-> F["Séparer vers des voies limitées, administration notamment"]
C -.-> G["Tester sévèrement le composant commun"]
Figure 12 : Ce que l’on factorise, ce n’est pas seulement l’accès aux données, mais les conditions d’autorisation et d’entrée à respecter.
8. Question 2(5) — compter les échecs et arrêter la force brute
Contre la force brute du code à 4 chiffres, on répond en 30 caractères ou moins le traitement qui entre dans le blanc d du tableau 5. Le seuil est 10.
L’exemple de réponse est le suivant.2
Un traitement qui verrouille le compte lorsque le nombre d’échecs consécutifs dépasse le seuil
8.1. Fondement — le nombre d’échecs est un état nécessaire au jugement de sécurité
Cela ne contredit pas le « sans état » de la question 1. Ne pas détenir l’état de conversation des appels d’API comme session serveur, et persister le nombre d’échecs nécessaire au jugement de sécurité, sont deux choses distinctes.
flowchart TB
accTitle: Présence ou absence d'une limite de tentatives
accDescr: Conserver le nombre d'échecs et verrouiller au-delà du seuil arrête la devinette en ligne illimitée.
A["Échec du contrôle du code"] --> B["Mettre à jour le nombre d'échecs du compte"]
B --> C{"Le seuil est-il dépassé ?"}
C -->|"oui"| D["Verrouiller le compte"]
C -->|"non"| E["Autoriser les tentatives restantes"]
F["Sans limite, on peut continuer d'essayer"] -.-> A
Figure 13 : Présence ou absence d’une limite. La limitation du nombre d’échecs arrête pratiquement la force brute.
8.2. Complément pratique — se préparer aussi à l’éviction par verrouillage
Une limite par compte est nécessaire, mais si l’attaquant connaît l’identifiant d’un autre utilisateur, il peut échouer exprès jusqu’au seuil et évincer l’utilisateur légitime. En pratique, on combine donc les contrôles suivants.
| Contrôle | Rôle |
|---|---|
| Nombre d’échecs par compte | Arrêter la force brute sur un seul compte |
| Délais d’attente progressifs | Tolérer les fautes de frappe de l’utilisateur légitime tout en ralentissant l’attaque |
| Contrôle par IP source, appareil, ASN, etc. | Freiner une attaque qui essaie peu de fois sur de nombreux comptes |
| Jugement fondé sur le risque | Restreindre plus fortement une région, un appareil ou une vitesse inhabituels |
| Notification à l’utilisateur | Permettre de remarquer une attaque ou une mauvaise manipulation |
| Procédure de récupération sûre | Ne pas faire du guichet de déverrouillage une voie d’attaque |
De plus, il ne faut pas ramener le nombre d’échecs à 0 lors d’un renvoi du code. Sinon l’attaquant peut faire renaître le quota de tentatives à chaque appel de l’API de renvoi. Le NIST SP 800-63B en vigueur demande aussi de ne pas réinitialiser le nombre d’échecs même en générant un nouveau secret d’authentification4.
8.3. Protéger ensemble réémission, réutilisation et API d’envoi
L’énoncé met l’accent sur la date d’expiration, mais en pratique il faut aussi les points suivants.
- Invalider immédiatement un code qui a réussi
- Refuser la réutilisation du même code
- Ne pas laisser le code lui-même dans les journaux
- Faire des réponses qui ne permettent pas de déduire l’existence de l’utilisateur d’après le succès ou l’échec du contrôle
- Placer aussi une limite de tentatives sur l’API d’envoi du code
Dès que l’on utilise un secret court, on ne peut pas confier la sécurité à la seule génération aléatoire.
flowchart TB
accTitle: Contre-mesures pour le code d'authentification
accDescr: Outre le nombre de candidats et la durée de validité, combiner conservation du nombre de tentatives, invalidation après succès, notification et procédure de récupération.
A["Émettre et réémettre le code"] --> B["Ne pas réinitialiser le nombre d'échecs"]
B --> C["Contrôler en limitant le nombre et la vitesse"]
C --> D{"Le contrôle a-t-il réussi ?"}
D -->|"oui"| E["Invalider le code immédiatement"]
D -->|"non"| F["Enregistrement d'échec, délai, verrouillage"]
F --> G["Notification et procédure de récupération sûre"]
A -.-> H["Limiter aussi l'API d'envoi, ne pas journaliser le code"]
Figure 14 : Contre-mesures pour le code d’authentification. On combine contrôle des tentatives et exploitation, pas seulement le nombre de chiffres et le délai d’expiration.
9. Question 3(1) — confirmer l’exécution de l’instruction de vérification dans les journaux d’accès
Essentiel de la réponse
La question 3(1) demande ce qu’il faut implémenter sur le serveur de test pour confirmer que la commande a été exécutée.
L’exemple de réponse est le suivant.
Un mécanisme qui enregistre et vérifie les accès à index.html du serveur de test2
9.1. Fondement — observer que l’on est allé jusqu’à la dernière instruction de vérification
Après le lancement du service, une vulnérabilité critique V est publiée dans la bibliothèque open source H, largement utilisée. Le déroulement de l’énoncé est le suivant.
- L’attaquant envoie une chaîne contenant un JNDI Lookup dans un en-tête HTTP
- Le serveur cible écrit cette valeur dans le journal
- La bibliothèque vulnérable évalue le JNDI Lookup et interroge le serveur LDAP d’attaque
- La réponse LDAP renvoie l’URL du serveur HTTP d’attaque
- Le serveur cible récupère le fichier de classe et exécute la commande
On peut le lire comme une attaque de type Log4Shell (CVE-2021-44228) dont le nom propre est tu. L’explication d’Apache la décrit aussi comme une vulnérabilité permettant d’exécuter du code arbitraire chargé depuis un serveur LDAP, si l’attaquant contrôle un message de journal ou un paramètre9.
flowchart TB
accTitle: Flux de confirmation d'une vulnérabilité de type Log4Shell
accDescr: Confirmer dans les journaux non seulement la référence JNDI et la récupération de classe, mais aussi l'obtention de index.html par la commande de vérification.
A["Entrée externe dans un en-tête HTTP"] --> B["Traitement des journaux du serveur cible"]
B --> C["Interroger LDAP via JNDI"]
C --> D["Recevoir l'URL de récupération de la classe"]
D --> E["Le serveur cible récupère la classe"]
E --> F["Exécuter l'instruction de vérification sur le serveur cible"]
F --> G["Obtenir index.html du serveur de test"]
G --> H["Enregistrer et vérifier cet accès"]
Figure 15 : Flux de confirmation d’une vulnérabilité de type Log4Shell. On confirme l’arrivée par l’enregistrement d’un accès HTTP, pas par une instruction destructrice.
L’instruction de vérification ne provoque qu’un accès HTTP inoffensif
La société G exécute un code de vérification sans impact sur le système, pour confirmer si la vulnérabilité V est exploitable depuis l’extérieur. L’instruction effectuée par ce code se limite à obtenir index.html du serveur de test.
Si le journal d’accès du serveur web conserve un GET provenant du serveur cible, on peut confirmer qu’au moins la chaîne suivante a abouti.
requête HTTP externe
-> traitement des journaux
-> JNDI Lookup
-> réponse LDAP
-> récupération de la classe
-> exécution de la commande de vérification
-> accès HTTP au serveur de test
9.2. Pourquoi le journal du serveur de test, et non l’affichage à l’écran ?
La cible de l’attaque est un serveur. Il n’y a pas forcément de changement visible dans le navigateur de l’utilisateur. De plus, même si la vulnérabilité existe, une communication sortante intermédiaire peut être arrêtée par un pare-feu.
Enregistrer l’accès côté serveur de test fournit une preuve observable que l’on est sorti du serveur cible vers l’extérieur.
9.3. Complément pratique — obtenir l’approbation et confirmer avec un effet de bord minimal
Pour une vérification du même type en pratique, on respecte nécessairement les points suivants.
- Obtenir l’approbation explicite du propriétaire du système cible
- Choisir une méthode de vérification sans impact en production, ou avec un impact acceptable
- Ne pas utiliser d’instructions destructrices (écriture, suppression, changement de configuration, etc.)
- Gérer soi-même le domaine et le serveur de vérification
- Enregistrer l’heure de vérification, la source, la cible et le rappel attendu
- Après la vérification, retirer les serveurs LDAP et HTTP temporaires et les identifiants
« Confirmer une exécution de code arbitraire » et « exécuter un code dangereux quelconque » ne sont pas la même chose. On se tient à l’effet de bord minimal qui atteint l’objectif.
flowchart TB
accTitle: Limiter la vérification à un effet de bord minimal
accDescr: Obtenir l'approbation, fixer une méthode de confirmation inoffensive et des conditions d'observation, puis retirer l'environnement de vérification et les identifiants après exécution.
A["Approbation explicite du propriétaire"] --> B["Fixer l'impact et les conditions d'observation"]
B --> C["Enregistrer l'accès sur un serveur sous contrôle"]
C --> D["Recouper avec l'heure et la source attendues"]
D --> E["Retirer l'environnement de vérification et les identifiants"]
B -.-> F["Pas d'écriture, de suppression ni de changement de configuration"]
Figure 16 : Décider d’abord le fait à observer, et inclure dans la procédure la confirmation inoffensive et le nettoyage.
10. Questions 3(2) à 3(4) — décider le lieu d’inspection, le motif et le comportement du WAF
10.1. Question 3(2) — les deux cibles d’inspection sont Header
Le WAF du service N permet de choisir comme cible d’inspection GET, POST, PUT, ANY, Header, COOKIE, Multipart.
Le code d’attaque entre dans la valeur de l’en-tête HTTP x-api-version. Donc les blancs e et f du tableau 6 sont tous deux Header.2
Le fondement est l’endroit où se trouve la chaîne d’attaque
Ici, plus que la culture générale, il s’agit de lire le flux de données de l’énoncé.
emplacement de la chaîne d'attaque :
en-tête x-api-version
|
v
cible d'inspection du WAF :
Header
Dans ce problème, ANY désigne l’inspection des valeurs de paramètres de toutes les méthodes ; c’est distinct de Header, qui inspecte les en-têtes.1
Ce n’est ni un paramètre GET ni le corps POST. On ne choisit pas « ANY parce que cela ressemble à une attaque » d’après la liste des fonctions du WAF : on répond l’endroit où l’énoncé dit que l’attaquant a mis la valeur.
flowchart TB
accTitle: Choisir le lieu d'inspection du WAF
accDescr: Décider la cible d'inspection du WAF d'après l'endroit où l'énoncé stocke la chaîne d'attaque, et non d'après le nom de l'attaque.
A["Lire l'emplacement de stockage de la chaîne d'attaque"] --> B["En-tête x-api-version"]
B --> C["La cible d'inspection est Header"]
C --> D["Vers un motif qui inclut majuscules et minuscules"]
E["ANY concerne les paramètres de toutes les méthodes"] -.-> C
Figure 17 : Ne pas deviner d’après le nom de l’attaque ; faire correspondre l’emplacement « en-tête » à la cible d’inspection.
10.2. Question 3(3) — autoriser majuscules et minuscules pour chaque caractère
Le premier projet était, conceptuellement, la règle suivante.
Header \Wjndi\W blocage
Header \Wldap\W blocage
Mais en permutant majuscules et minuscules, comme jNdI, on contourne un motif en minuscules seulement.
L’exemple de réponse de la question 3(3) est l’un des deux suivants.2
\W[jJ][nN][dD][iI]\W
\W(j|J)(n|N)(d|D)(i|I)\W
Dans le livret d’examen, la barre oblique inverse peut apparaître comme le signe yen dans une police japonaise, mais en expression régulière il s’agit de \W. \W correspond à un caractère autre qu’une lettre, un chiffre ou un trait de soulignement. Dans la syntaxe JNDI Lookup, des caractères non-mot tels que ${ ou : apparaissent avant et après jndi ; on les inclut dans la recherche.
Le même raisonnement permet de rendre le côté ldap insensible à la casse.
\W[lL][dD][aA][pP]\W
10.3. Question 3(4) — la détection sert à éviter un blocage par erreur
Sur la règle WAF après modification, M. Z, spécialiste agréé, conseille de mettre le comportement en « détection » plutôt qu’en « blocage » pendant une période donnée après le début de l’exploitation en production.
La question demande, en 25 caractères ou moins chacun, l’avantage de la détection et ce qu’il faut mettre en œuvre pour minimiser les dommages.
L’exemple de réponse est le suivant.2
| Élément | Essentiel de la réponse |
|---|---|
| Avantage | Pouvoir empêcher un blocage causé par un faux positif |
| Contenu à mettre en œuvre | Examiner, à réception d’une alerte, s’il s’agit d’une attaque |
Fondement — la détection va de pair avec une exploitation qui examine les alertes
En mode détection, le trafic qui correspond à la règle est laissé passer, tout en l’enregistrant dans le journal et en émettant une alerte. Même si une chaîne jndi ou ldap apparaît par hasard dans un appel d’API normal, on n’arrête pas d’emblée l’activité.
En échange, l’exploitation a besoin de ce qui suit.
réception d'alerte
|
v
examiner la requête cible
|
+-- trafic normal -> resserrer la règle, examiner des conditions d'exception
|
+-- attaque -> isoler la cible, préserver les journaux, enquêter sur l'impact, passer au blocage
Si personne ne regarde les alertes, le mode détection n’a aucun effet défensif. La détection va de pair avec une exploitation qui observe et juge.
10.4. Complément pratique — observer, ajuster, puis passer au blocage
La procédure d’introduction habituelle est la suivante.
- Appliquer le mode détection au trafic réel
- Classer faux positifs et détections justes
- Ajuster l’en-tête cible, le chemin, l’API, les frontières de caractères, etc.
- Confirmer que l’impact sur le trafic normal est acceptable
- Passer en mode blocage
- Surveiller le nombre de blocages et l’impact métier
Cela dit, c’est le principe en temps normal. Si la vulnérabilité est critique, déjà exploitée, et qu’il n’existe pas de moyen de substitution, on peut juger que le préjudice d’une compromission dépasse l’arrêt par faux positif, et bloquer d’emblée. Dans la situation de l’examen, on choisit d’abord la détection pour vérifier que le service reste utilisable comme jusqu’alors.
flowchart TB
accTitle: Du mode détection au mode blocage du WAF
accDescr: Examiner les alertes pendant la détection, ajuster les faux positifs et traiter les attaques, puis continuer de surveiller après le passage au blocage.
A["Observer le trafic en mode détection"] --> B{"Contenu de l'alerte"}
B -->|"faux positif"| C["Ajuster la règle ou les conditions d'exception"]
C --> A
B -->|"attaque"| D["Isoler, préserver les journaux, enquêter sur l'impact"]
D --> E["Passer au blocage"]
A --> F["Confirmer l'impact sur le trafic normal"]
F --> E
E --> G["Surveiller le nombre de blocages et l'impact métier"]
Figure 18 : De la détection au blocage. D’abord observer et ajuster, confirmer que l’impact est acceptable, puis passer au blocage.
11. Réponse pratique à une vulnérabilité — gagner du temps avec le WAF, avancer la mise à jour et l’enquête
Dans l’énoncé, le site officiel de la bibliothèque H n’avait encore ni version corrigée ni mesure provisoire, et une règle WAF exhaustive du fournisseur cloud pouvait prendre jusqu’à 72 heures. La société G confirme donc elle-même l’impact, et bloque temporairement au moins les motifs déjà connus.
L’examen a demandé la règle WAF provisoire et son exploitation, mais un WAF ne corrige pas la vulnérabilité elle-même. Confirmation d’impact, atténuation provisoire et correction de fond avancent, là où c’est possible, sans s’attendre. L’ensemble de la réponse, y compris les compléments pratiques, est le suivant.
| Étape | Objectif | Réponse dans ce problème et en pratique |
|---|---|---|
| Confirmation d’impact | Juger si l’on est réellement en danger | Confirmer la possibilité d’exploitation externe par un rappel inoffensif |
| Atténuation provisoire | Gagner du temps jusqu’à la correction | Règle WAF, détection et blocage, restriction des communications sortantes |
| Correction de fond | Éliminer la cause vulnérable | Mettre à jour vers la version corrigée de la bibliothèque |
| Confirmation a posteriori | Vérifier si l’on a déjà été exploité | Enquête dans les journaux WAF, application, DNS, proxy, etc. |
| Prévention de récidive | Accélérer le jugement la prochaine fois | Inventaire des dépendances, SBOM, procédure de mise à jour, voies de contact |
11.1. Ne pas prendre une règle provisoire pour une contre-mesure Log4Shell complète
L’examen demande l’expression régulière qui correspond à la méthode de contournement indiquée dans l’énoncé. Dans une attaque réelle, il peut y avoir des variantes difficiles à couvrir par une signature seule : découpage de chaîne, autre Lookup, encodage, autre protocole, etc.
Donc, en pratique, le positionnement est le suivant.
- Arrêter provisoirement par WAF les motifs d’attaque déjà connus
- Vérifier si la bibliothèque concernée est réellement présente
- Restreindre LDAP, RMI et HTTP sortants inutiles
- Mettre à jour vers la version corrigée
- Après la mise à jour, consulter encore les journaux et enquêter sur une éventuelle compromission
Le WAF est la couche qui gagne du temps jusqu’à la parution de la version corrigée.
flowchart TB
accTitle: Positionnement du WAF
accDescr: La détection observe en laissant passer le trafic ; le blocage et la restriction des communications sortantes atténuent, pendant que la mise à jour élimine la cause.
A["Publication d'une vulnérabilité critique"] --> B["Confirmation d'impact et réponse provisoire"]
B --> C["Obtenir journaux et alertes par la détection"]
B --> D["Blocage et restriction des communications sortantes"]
C --> E["Ajuster et traiter d'après l'observation"]
D --> F["Mettre à jour vers la version corrigée de la bibliothèque"]
E --> F
F --> G["Confirmer a posteriori l'absence ou la présence d'une compromission"]
Figure 19 : Positionnement du WAF. Le WAF gagne du temps jusqu’à la version corrigée ; la contre-mesure de fond est la mise à jour.
11.2. Préparation en temps normal — connaître les bibliothèques utilisées et leurs lieux de déploiement
Dans l’énoncé, même si la société G demande à la société F si elle utilise la bibliothèque H, une analyse détaillée de la configuration est nécessaire et la réponse prend du temps.
En pratique, commencer à chercher des fichiers JAR seulement après la publication d’une vulnérabilité critique retarde la réponse. Il faut au moins détenir en temps normal les éléments suivants.
- La liste des dépendances directes et transitives
- Les composants réellement inclus dans les livrables, avec leurs versions
- Vers quels services, conteneurs et postes ils sont déployés
- La procédure pour mettre à jour une bibliothèque dépendante, reconstruire et redistribuer
- La voie de contact pour approuver un changement d’urgence
- Les destinations de communication sortante autorisées, et l’impact si on les arrête
- L’emplacement de conservation des journaux et la façon de les interroger
Le SBOM n’est pas une fin. C’est un index pour répondre en peu de temps à « cette vulnérabilité touche quels systèmes en cours d’exécution ? ».
flowchart TB
accTitle: Relier les dépendances aux systèmes en cours d'exécution
accDescr: Faire correspondre en temps normal composants dépendants et lieux de distribution, pour accélérer l'enquête et le jugement de mise à jour après publication d'une vulnérabilité.
A["Liste des dépendances directes et transitives"] --> B["Versions réelles des livrables"]
B --> C["Services en production et lieux de déploiement"]
C --> D["Juger rapidement les cibles d'impact"]
D --> E["Approbation, reconstruction, redistribution"]
C -.-> F["Connaître aussi les destinations de communication et de conservation des journaux"]
Figure 20 : Le SBOM n’a pas pour but d’être collecté ; c’est un index pour juger vite les cibles d’impact et la méthode de mise à jour.
11.3. Confirmation a posteriori — ne pas terminer l’enquête de compromission au seul motif d’une mise à jour
Il est possible que l’on ait déjà été attaqué autour de la publication de la vulnérabilité. Mettre à jour vers la version corrigée arrête les exploitations futures, mais n’efface pas des identifiants déjà compromis ni une porte dérobée déjà installée.
Pour un type Log4Shell, on examine au moins les angles suivants.
- Requêtes HTTP contenant une chaîne suspecte indiquant JNDI ou LDAP
- Communications du serveur d’application vers LDAP, RMI ou HTTP externes
- Démarrage d’un processus enfant inhabituel
- Création d’un JAR, d’une classe, d’un script ou d’un exécutable suspects
- Accès à des identifiants cloud ou à des variables d’environnement
- Changements d’authentification ou d’autorisation, et envois vers l’extérieur, avant et après la mise à jour
L’important est de ne pas conclure « nous n’avons pas été attaqués » d’après les seuls journaux WAF. Il existe des voies internes qui ne passent pas par le WAF, et des journaux qui n’ont pas été conservés dans le passé.
flowchart TB
accTitle: Séparer mise à jour et enquête de compromission
accDescr: Empêcher les exploitations futures par la mise à jour vers la version corrigée, et enquêter sur une compromission déjà survenue, sont deux nécessités distinctes.
A["Mettre à jour vers la version corrigée"] --> B["Arrêter les exploitations futures"]
C["Examiner les enregistrements avant et après la mise à jour"] --> D["Recouper communications, processus et fichiers"]
D --> E["Vérifier identifiants et envois vers l'extérieur"]
B -.-> F["Une compromission passée ne disparaît pas"]
F -.-> C
Figure 21 : Avancer séparément la correction de la cause et l’enquête sur une compromission déjà survenue.
12. Rédiger les réponses — répondre à l’écart avec la spécification, dans les termes de l’énoncé
Ce problème est moins une question de connaissances qu’une question de lecture de l’écart entre spécification et implémentation.
12.1 Séparer la « spécification » et l’« implémentation » du tableau
Dans le problème de status, une valeur absente de la spécification d’API passe dans l’implémentation.
spécification :
mid / name / age
implémentation :
envoyer tous les paramètres reçus à P
Dès que cet écart est visible, on comprend que le blanc c est le module commun P.
12.2 Tracer une ligne sur la valeur que l’attaquant a changée
Les valeurs changées dans chaque attaque sont les suivantes.
algde l’en-tête JWT- Identifiant d’utilisateur de la charge utile JWT
middes paramètres d’APIstatushors spécificationotpde l’API d’authentificationx-api-versionde l’en-tête HTTP
Presque toutes les questions demandent « où cette valeur devrait-elle être validée ? ».
12.3 Ramener la réponse aux termes de l’énoncé
En pratique, on peut dire « BOLA », « Mass Assignment », « rate limiting ». Mais ce que la question demande, c’est un traitement concret aligné sur la structure de l’énoncé.
Mauvais exemple :
Effectuer l’autorisation de façon appropriée.
Bon exemple :
Vérifier si l’identifiant d’utilisateur contenu dans le JWT correspond à la valeur de mid.
Mauvais exemple :
Mettre en place une contre-mesure de force brute.
Bon exemple :
Verrouiller le compte lorsque le nombre d’échecs consécutifs dépasse le seuil.
Connaître le nom abstrait ne suffit pas à produire une réponse notée dans la limite de caractères.
12.4 Pour le WAF, suivre « où cela a été mis »
La cible d’inspection du WAF se décide d’après l’emplacement de stockage de la chaîne d’attaque, non d’après le type d’attaque.
mis dans l'en-tête x-api-version
↓
la cible d'inspection est Header
Le commentaire de notation indique un taux de réussite d’ensemble moyen, et un taux un peu plus bas pour les questions 2(2) et 3(1).3 Le taux un peu plus bas de la question 3(1) vient aussi de nombreuses réponses qui ne correspondaient pas au flux d’attaque de la figure 6. Réécrire simplement la procédure d’attaque en flèches fait déjà apparaître ce qu’il faut observer.
flowchart TB
accTitle: Revenir de l'énoncé à la réponse
accDescr: Suivre l'écart spécification/implémentation, la valeur changée et le traitement auquel on a fait confiance, puis écrire un traitement concret dans les termes de l'énoncé.
A["Aligner spécification et implémentation"] --> B["Identifier la valeur changée"]
B --> C["Suivre où l'on a fait confiance"]
C --> D["Décider le traitement à ajouter"]
D --> E["Revenir aux termes et à la limite de caractères de l'énoncé"]
Figure 22 : Ne pas se contenter d’apprendre des termes ; suivre le flux des valeurs et répondre par un traitement concret.
13. Checklist à utiliser pour une revue d’API en pratique
Voici une checklist pour ramener ce problème vers une revue de conception et de code réelle.
Validation JWT
- Les algorithmes de signature autorisés sont fixés dans la configuration serveur
noneet les algorithmes imprévus sont refusés- Signature,
iss,aud,exp,nbfsont validés selon l’usage - On ne confond pas jeton d’identité, jeton d’accès et jeton de rafraîchissement
- Il existe une procédure de rotation des clés et de révocation
- On n’a pas mis d’informations à tenir secrètes dans la charge utile JWT
Autorisation au niveau de l’objet
- Changer un identifiant dans la requête ne permet pas d’atteindre les données d’autrui
- L’autorisation est faite pour la liste, le détail, la mise à jour, la suppression et le téléchargement
- L’autorisation est mise en œuvre dans la couche commune qui atteint les données, non dans l’écran
- Pour une API dédiée à soi-même, on a examiné si l’identifiant cible peut être dérivé du jeton
- Les opérations d’administrateur ont une politique distincte de l’API utilisateur ordinaire
Autorisation au niveau de la propriété
- Le type d’entrée externe et l’entité de base de données sont séparés
- Les champs modifiables sont énumérés en liste d’autorisation
- Les propriétés hors spécification sont refusées ou auditées
- Des états tels que droits, facturation, approbation, propriétaire ne peuvent pas être changés depuis une entrée utilisateur
- La réponse ne contient pas non plus de propriétés confidentielles inutiles
Tentatives d’authentification
- Il existe une limite du nombre d’échecs par compte
- Il existe un délai progressif ou un contrôle par source
- Une réémission du code ne réinitialise pas le nombre d’échecs
- Le code d’authentification n’est utilisable qu’une fois
- On ne laisse pas le code d’authentification ni le mot de passe dans les journaux
- La procédure de déverrouillage et de récupération n’est pas devenue une autre voie d’authentification faible
Vulnérabilité critique d’une bibliothèque dépendante
- On peut faire correspondre services en cours d’exécution et versions des dépendances
- Il existe une procédure pour vérifier l’impact de façon inoffensive
- On peut appliquer une mesure provisoire telle qu’un WAF ou une restriction des communications sortantes
- Il existe une exploitation où un responsable consulte les alertes de détection
- Il existe une voie de publication d’urgence pour mettre à jour vers la version corrigée
- On enquête dans les journaux sur une éventuelle exploitation avant la mise à jour
flowchart TB
accTitle: Une revue essaie ce qui vient après le cas nominal
accDescr: Au-delà du succès d'une requête normale, confirmer séparément le changement d'identifiant, de champ et les tentatives répétées, pour valider la contre-mesure de la couche commune.
A["Confirmer le succès d'une requête normale"] --> B["Confirmer en ne changeant que l'identifiant cible"]
B --> C["Confirmer en ajoutant un champ de mise à jour inconnu"]
C --> D["Répéter échec d'authentification et réémission"]
D --> E["Confirmer refus, enregistrement et récupération"]
E -.-> F["Traiter chacune comme une vérification distincte"]
Figure 23 : Partir du succès du cas nominal, et confirmer que chaque frontière refuse réellement.
14. Conclusion — ne pas omettre la frontière de confiance suivante
La question 1 de l’après-midi de la session de printemps de l’année Reiwa 6 est un problème qui demande de lire un à un les points de sécurité des API, en les séparant.
Utiliser JWT ne signifie pas une authentification sûre. Si l’on laisse l’attaquant choisir l’algorithme de signature, on peut réécrire l’identifiant d’utilisateur.
Une signature JWT correcte ne signifie pas une autorisation correcte. Si l’on fait confiance au mid de la requête, un utilisateur légitime peut accéder aux informations d’autrui.
Pouvoir mettre à jour son propre objet ne signifie pas que l’on a le droit de changer toutes les propriétés. Si l’on lie automatiquement un état interne tel que status, on peut réécrire des droits ou un état de facturation.
Le fait qu’un code d’authentification ait une date d’expiration ne signifie pas qu’il résiste à la force brute. Il faut calculer le nombre de candidats et la vitesse de tentative, et limiter le nombre d’échecs.
Mettre une règle dans un WAF ne signifie pas que l’on a corrigé la vulnérabilité. On gagne du temps par la détection et le blocage, on confirme l’impact, et au bout du compte on met à jour la bibliothèque.
flowchart TB
accTitle: Correspondance entre vulnérabilités et contre-mesures
accDescr: Prévoir une contre-mesure pour chaque frontière : jeton et tentatives d'authentification, cible et champs de mise à jour, exécution depuis une entrée externe.
A["Séparer les frontières auxquelles on fait confiance"] --> B["Jeton et tentatives d'authentification"]
A --> C["Données cibles et champs de mise à jour"]
A --> D["Exécution depuis une entrée externe"]
B --> E["Fixer les algorithmes autorisés et limiter les tentatives"]
C --> F["Recouper le sujet et limiter le DTO de mise à jour"]
D --> G["Atténuation provisoire et mise à jour de la bibliothèque"]
Figure 24 : Correspondance vulnérabilités et contre-mesures. On sépare la contre-mesure pour chaque frontière rompue.
Le principe qui traverse ce problème est unique.
Ne pas prendre le succès de la validation précédente comme raison d’omettre la frontière de confiance suivante.
Dans les articles précédents de la série, nous expliquons le XSS stocké de la question 1 de l’après-midi de l’automne Reiwa 5 et l’exfiltration d’informations depuis le Wi-Fi invité de la question 2 de l’après-midi de l’automne Reiwa 5. Pour les points de contrôle d’un site web dans son ensemble, voir aussi Utiliser le guide de l’IPA « Comment créer un site web sécurisé » comme checklist.
flowchart TB
accTitle: Conclusion finale
accDescr: Le succès de la vérification précédente ne doit pas servir de raison d'omettre la vérification suivante ni les contre-mesures d'exploitation.
A["Succès de la validation précédente"] --> B{"La vérification suivante est-elle aussi satisfaite ?"}
B -->|"la confirmer séparément"| C["Empiler les jugements frontière par frontière"]
B -->|"l'omettre parce que la précédente a réussi"| D["Il reste une frontière non vérifiée"]
C --> E["Le répercuter dans la conception et la validation quotidiennes"]
Figure 25 : Conclusion finale. Les frontières de confiance se confirment par étapes ; on n’en omet aucune.
Références
-
IPA, Livret de questions de l’après-midi de l’examen de spécialiste agréé en sécurité de l’information, session de printemps de l’année Reiwa 6. L’énoncé traité dans cet article. ↩ ↩2 ↩3 ↩4
-
IPA, Exemples de réponses de l’après-midi de l’examen de spécialiste agréé en sécurité de l’information, session de printemps de l’année Reiwa 6. Les exemples de réponses officiels de chaque question. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12
-
IPA, Commentaire de notation de l’après-midi de l’examen de spécialiste agréé en sécurité de l’information, session de printemps de l’année Reiwa 6. Explication des taux de réussite et des tendances d’erreur. ↩ ↩2 ↩3
-
NIST, SP 800-63B: Authentication and Authenticator Management. Indique le nombre de chiffres des secrets de courte durée, la limitation du nombre de tentatives, le nombre d’échecs lors d’une réémission, et le fait de ne pas utiliser le courrier électronique comme authentification hors bande. ↩ ↩2
-
RFC Editor, RFC 7519: JSON Web Token (JWT). Spécification JWT, y compris Unsecured JWT et
alg=none. ↩ -
RFC Editor, RFC 8725: JSON Web Token Best Current Practices. BCP qui fixe les algorithmes autorisés et la validation de l’émetteur, du sujet et de l’audience. ↩
-
OWASP, API1:2023 Broken Object Level Authorization. Explique la nécessité de confirmer l’autorisation pour chaque identifiant d’objet spécifié par l’utilisateur. ↩
-
OWASP, API3:2023 Broken Object Property Level Authorization. Explique les failles d’autorisation au niveau de la propriété, y compris Mass Assignment, et les contre-mesures. ↩
-
Apache Logging Services, Security. Explique l’impact de CVE-2021-44228, l’exécution de code via JNDI et LDAP, et les versions corrigées. ↩
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
Examen de spécialiste agréé en sécurité de l'information, automne 2023 (Reiwa 5), question 2 de l'après-midi — Les fichiers qui sortent par le Wi-Fi invité
La question 2 de l'après-midi de l'examen RISS automne 2023 montre comment une entreprise qui a interdit les clés USB perd des fichiers p...
Examen de spécialiste certifié en sécurité de l'information, automne Reiwa 5, question 1 de l'après-midi — le XSS stocké qui réduit 16 avis à 2
À partir de la question 1 de l'après-midi de l'examen de spécialiste certifié en sécurité de l'information, session d'automne Reiwa 5, ce...
Ce que les clients d'un site web devraient aussi savoir — Utiliser le guide de l'IPA « Comment créer un site web sécurisé » comme checklist
Sur quels critères vérifier la sécurité du site web de votre entreprise ? Cet article explique les 11 vulnérabilités et contre-mesures co...
Top 10 des menaces de sécurité de l'information 2026 — Comment lire le classement, et ce que les PME doivent vraiment mettre en œuvre
Dans le « Top 10 des menaces de sécurité de l'information 2026 » de l'IPA, les attaques par ransomware occupent la première place pour la...
Sécurité des PME : par où commencer ? — Guide de lecture de la version 4.0 des « Directives de sécurité de l'information pour les PME » de l'IPA
Par où une PME doit-elle commencer sa démarche de sécurité ? En s'appuyant sur la version 4.0 des « Directives de sécurité de l'informati...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Création de sites web
Dans les API de membres et les intégrations avec des applications mobiles, la validation des JWT, l'autorisation au niveau de l'objet et la limitation des propriétés modifiables déterminent directement la sécurité du système web.
Conseil technique et revue de conception
Identifier les failles d'autorisation dans des API existantes, évaluer le périmètre d'impact des bibliothèques dépendantes, et élaborer des règles WAF provisoires par une revue de conception relèvent du champ du conseil technique.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- La vérification de la signature du JWT a réussi, alors pourquoi peut-on quand même usurper l'identité d'autrui ?
- Dans ce problème, la bibliothèque de gestion des JWT acceptait la valeur de alg dans l'en-tête du JWT exactement telle que l'attaquant l'avait spécifiée, et traitait un JWT avec alg=none comme valide, sans signature. Par conséquent, même en réécrivant l'identifiant d'utilisateur dans la charge utile, la validation réussissait. La réponse de l'examen consiste à prendre pour cible de vérification le alg de l'en-tête du JWT, et à confirmer que sa valeur n'est pas NONE. En pratique, cependant, rejeter uniquement NONE ne suffit pas. Il faut fixer, dans la configuration côté serveur, les algorithmes autorisés (par exemple RS256), sans jamais utiliser directement l'algorithme déclaré par le jeton pour effectuer ce choix. Il faut aussi vérifier, selon l'usage, l'émetteur (issuer), l'audience, la date d'expiration, le sujet (subject), etc.
- Comparer l'identifiant d'utilisateur contenu dans le JWT avec le mid de la requête suffit-il comme mesure d'autorisation ?
- Pour la réponse attendue à cet examen, cela suffit. En vérifiant, dans le module commun P, que l'identifiant d'utilisateur contenu dans le JWT correspond au mid, on arrête une attaque qui spécifie le mid d'un autre utilisateur. Cependant, pour une API qui ne traite que les informations propres à l'appelant, il est plus sûr, en pratique, de ne jamais recevoir le mid du client et de déterminer l'identifiant d'utilisateur à partir du sujet (subject) du JWT validé. En utilisant par exemple GET /users/me ou PUT /users/me, on réduit le risque même d'oublier d'implémenter la comparaison. Une API où un administrateur agit sur un autre utilisateur doit être séparée en un point de terminaison distinct, avec sa propre politique d'autorisation.
- Pourquoi une validation ordinaire des valeurs saisies ne suffit-elle pas à empêcher l'attaque qui ajoute status ?
- Parce que même en validant la longueur de name ou la plage de age, cela ne protège rien si status — un champ qui n'aurait jamais dû être accepté — est automatiquement lié et transmis à l'objet interne. Le problème n'est pas le format de la valeur, mais l'autorisation au niveau de la propriété : l'utilisateur est-il autorisé à modifier cette propriété ? Le type de saisie utilisé pour la mise à jour ne doit définir que name et age, et rejeter toute propriété inconnue. L'état de facturation ne doit être modifié qu'à partir d'événements dignes de confiance côté serveur, comme le résultat réussi du service de paiement.
- Le code d'authentification à 4 chiffres expire au bout de 10 minutes ; pourquoi reste-t-il dangereux ?
- Parce qu'il n'existe que 10 000 candidats possibles, de 0000 à 9999, et qu'à raison de 10 tentatives par seconde, un attaquant réussit en moyenne au bout de 5 000 tentatives, soit 500 secondes. Or la durée de validité de 10 minutes équivaut à 600 secondes : en essayant des candidats non répétés dans l'ordre, il est possible d'en vérifier 6 000 dans ce laps de temps. La durée d'expiration seule ne suffit pas à arrêter une attaque par force brute. Il faut concevoir ensemble le nombre de candidats, la vitesse de tentative et le plafond du nombre de tentatives.
- La mesure attendue par la question est le verrouillage du compte ; un simple verrouillage immédiat suffit-il aussi en pratique ?
- Non. Le blanc du problème appelle un traitement qui verrouille le compte lorsque le nombre d'échecs consécutifs dépasse un seuil, mais un verrouillage permanent et figé permet à lui seul à un attaquant de verrouiller délibérément le compte d'autrui, créant un déni de service. En pratique, on combine un compteur d'échecs par compte, des délais d'attente progressifs, une évaluation du risque liée à la source ou à l'appareil, des notifications, et une procédure de récupération. Il est également important que l'émission d'un nouveau code ne remette pas le compteur d'échecs à zéro.
- Quel est l'intérêt de configurer le WAF en mode détection plutôt qu'en mode blocage ?
- Cela permet de ne pas interrompre le trafic professionnel légitime, même lorsqu'une chaîne de caractères normale est faussement jugée comme une attaque. Dans la réponse attendue, l'avantage est de pouvoir éviter un blocage causé par un faux positif, et ce qu'il faut faire est d'examiner, à chaque alerte reçue, s'il s'agit réellement d'une attaque. Le mode détection n'est pas un réglage que l'on peut laisser sans surveillance. Il sert de période d'observation pendant laquelle on consulte les journaux pour écarter les faux positifs, ajuster les règles, puis passer au blocage. En cas d'urgence, lorsqu'une vulnérabilité critique connue est effectivement exploitée, il peut être justifié de bloquer d'emblée, en mettant ce choix en balance avec le risque pour la disponibilité.
- La bibliothèque H de ce problème est-elle Log4j ?
- L'énoncé tait le nom du produit, mais la séquence d'attaque — JNDI Lookup, serveur LDAP, récupération de classe depuis un serveur HTTP, chaîne intégrée dans un en-tête HTTP, et score de base CVSS v3.1 élevé — se lit naturellement comme une abstraction de la CVE-2021-44228, connue sous le nom de Log4Shell. Cet article explique cette correspondance, mais l'examen ne demande pas de citer le nom du produit. Il peut être résolu uniquement à partir de la procédure d'attaque donnée et de la spécification du WAF.
- Que faut-il retenir de ce problème pour sa propre pratique ?
- Que réussir l'authentification, que le JWT n'a pas été falsifié, qu'on est autorisé à accéder à l'objet cible et qu'on est autorisé à modifier la propriété cible sont quatre vérifications entièrement distinctes. De plus, un code d'authentification court exige une limitation du nombre de tentatives, et une vulnérabilité critique dans une bibliothèque impose de mener de front la vérification de l'impact, la protection provisoire et la correction de fond. L'essentiel, en pratique, tient à centraliser l'autorisation dans des composants communs, à faire du schéma de saisie une liste d'autorisation, à fixer côté serveur les conditions de validation du JWT, et à connaître ses bibliothèques dépendantes de façon à pouvoir les mettre à jour.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.