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: · · 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

Vue d'ensemble du problèmeLire 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.Requête de l'utilisateurContrôle du code d'authentificationÉmission et validation du JWTAPI utilisateurAutorisation du mid cibleAutorisation du status de mise à jourEnregistrement d'une entrée externe dans le journalBibliothèque vulnérableExé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.

Différence entre authentification et autorisationConfirmer 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.Authentification et validation du jetonDéterminer de qui vient la requêteA-t-on le droit d'atteindre ces données ?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 ».

  • alg est une politique de traitement cryptographique
  • mid est une autorisation au niveau de l’objet
  • status est une autorisation au niveau de la propriété
  • otp est 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.

Sans état et états conservésTraiter 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.Requête avec JWTIdentifier l'utilisateur à partir de cette seule requêteExécuter le traitement et répondreInformations utilisateur, facturation, nombre d'échecsAucune 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 ».

Ordre de grandeur temporel du code d'authentification à 4 chiffresDans l'approximation de l'examen, la moyenne est 500 secondes ; sans doublon, 60 pour cent des candidats tiennent dans les 600 secondes de validité.10 000 candidatsMoyenne d'environ 5 000 tentativesÀ 10 par seconde, environ 500 secondesPlus court que les 600 secondes de validité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.

  1. Changer le alg de l’en-tête de RS256 en NONE
  2. 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.

Déroulement de l'attaque JWT alg=noneSi l'attaquant change la méthode de validation et l'identifiant, une bibliothèque qui autorise none accepte le JWT falsifié.Obtenir un JWT valideChanger alg en noneChanger user vers un autre utilisateurLa bibliothèque omet la validation de signatureAccepter 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.

Validation JWT sûre et validation JWT dangereuseNe 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.nonouiRéception du JWTAlgorithme autorisé par le serveur ?RefuserValider la signature et chaque revendicationTraiter comme un sujet validéTraitement dangereuxOmettre 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é.

Signature JWT et confidentialité sont distinctesbase64url est une représentation lisible par un tiers ; la détection de falsification par signature et la confidentialité se pensent séparément.JWT signéLire l'en-tête et la charge utileDécoder le base64urlLe contenu n'est pas secretValider correctement la signatureVé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.

Attaque BOLALe 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.JWT à signature correcte (user01)API utilisateurmid modifié (user02)Pas de recoupement avec le sujetRé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 ».

Comment empêcher BOLAVé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.on reçoit midouinonAPI dédiée à soi-mêmeSujet du JWT validéComment décider l'identifiant cibleCorrespond au sujet ?Opérer sur ses propres donnéesRefuserDériver l'identifiant cible du sujet

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.

Mass AssignmentTransmettre jusqu'au status hors spécification au module commun et le mettre à jour permet à l'utilisateur de changer l'état de facturation.La spécification est mid, name, ageAjouter status=paidPasser tous les paramètres à PRépercuter tels quels dans les données internesL'é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.

  1. Ne placer dans le type d’entrée de mise à jour que les champs que l’utilisateur a le droit de changer
  2. 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.

Autorisation au niveau du champLimiter 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.ouinonDemande de mise à jour du profilSeulement name et age ?Mettre à jour uniquement les champs autorisésRefuser les champs inconnusNotification de paiement validéeRecoupement du paymentId et prévention des doublonsMettre à 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 mid ou un status quelconque, 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.

Rétrécir le contrat des composants communsInclure 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.API pour l'utilisateur ordinaireSujet validé et DTO de mise à jourUnifier l'autorisation dans le composant communOpérer sur les données autoriséesOpération sur un ID quelconque et une Map quelconqueSéparer vers des voies limitées, administration notammentTester 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.

Présence ou absence d'une limite de tentativesConserver le nombre d'échecs et verrouiller au-delà du seuil arrête la devinette en ligne illimitée.ouinonÉchec du contrôle du codeMettre à jour le nombre d'échecs du compteLe seuil est-il dépassé ?Verrouiller le compteAutoriser les tentatives restantesSans limite, on peut continuer d'essayer

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.

Contre-mesures pour le code d'authentificationOutre 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.ouinonÉmettre et réémettre le codeNe pas réinitialiser le nombre d'échecsContrôler en limitant le nombre et la vitesseLe contrôle a-t-il réussi ?Invalider le code immédiatementEnregistrement d'échec, délai, verrouillageNotification et procédure de récupération sûreLimiter 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.

  1. L’attaquant envoie une chaîne contenant un JNDI Lookup dans un en-tête HTTP
  2. Le serveur cible écrit cette valeur dans le journal
  3. La bibliothèque vulnérable évalue le JNDI Lookup et interroge le serveur LDAP d’attaque
  4. La réponse LDAP renvoie l’URL du serveur HTTP d’attaque
  5. 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.

Flux de confirmation d'une vulnérabilité de type Log4ShellConfirmer 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.Entrée externe dans un en-tête HTTPTraitement des journaux du serveur cibleInterroger LDAP via JNDIRecevoir l'URL de récupération de la classeLe serveur cible récupère la classeExécuter l'instruction de vérification sur le serveur cibleObtenir index.html du serveur de testEnregistrer 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.

Limiter la vérification à un effet de bord minimalObtenir 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.Approbation explicite du propriétaireFixer l'impact et les conditions d'observationEnregistrer l'accès sur un serveur sous contrôleRecouper avec l'heure et la source attenduesRetirer l'environnement de vérification et les identifiantsPas 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.

Choisir le lieu d'inspection du WAFDé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.Lire l'emplacement de stockage de la chaîne d'attaqueEn-tête x-api-versionLa cible d'inspection est HeaderVers un motif qui inclut majuscules et minusculesANY concerne les paramètres de toutes les méthodes

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.

  1. Appliquer le mode détection au trafic réel
  2. Classer faux positifs et détections justes
  3. Ajuster l’en-tête cible, le chemin, l’API, les frontières de caractères, etc.
  4. Confirmer que l’impact sur le trafic normal est acceptable
  5. Passer en mode blocage
  6. 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.

Du mode détection au mode blocage du WAFExaminer les alertes pendant la détection, ajuster les faux positifs et traiter les attaques, puis continuer de surveiller après le passage au blocage.faux positifattaqueObserver le trafic en mode détectionContenu de l'alerteAjuster la règle ou les conditions d'exceptionIsoler, préserver les journaux, enquêter sur l'impactPasser au blocageConfirmer l'impact sur le trafic normalSurveiller 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.

  1. Arrêter provisoirement par WAF les motifs d’attaque déjà connus
  2. Vérifier si la bibliothèque concernée est réellement présente
  3. Restreindre LDAP, RMI et HTTP sortants inutiles
  4. Mettre à jour vers la version corrigée
  5. 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.

Positionnement du WAFLa 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.Publication d'une vulnérabilité critiqueConfirmation d'impact et réponse provisoireObtenir journaux et alertes par la détectionBlocage et restriction des communications sortantesAjuster et traiter d'après l'observationMettre à jour vers la version corrigée de la bibliothèqueConfirmer 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 ? ».

Relier les dépendances aux systèmes en cours d'exécutionFaire 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é.Liste des dépendances directes et transitivesVersions réelles des livrablesServices en production et lieux de déploiementJuger rapidement les cibles d'impactApprobation, reconstruction, redistributionConnaî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é.

Séparer mise à jour et enquête de compromissionEmpê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.Mettre à jour vers la version corrigéeArrêter les exploitations futuresExaminer les enregistrements avant et après la mise à jourRecouper communications, processus et fichiersVérifier identifiants et envois vers l'extérieurUne compromission passée ne disparaît pas

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.

  • alg de l’en-tête JWT
  • Identifiant d’utilisateur de la charge utile JWT
  • mid des paramètres d’API
  • status hors spécification
  • otp de l’API d’authentification
  • x-api-version de 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.

Revenir de l'énoncé à la réponseSuivre 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é.Aligner spécification et implémentationIdentifier la valeur changéeSuivre où l'on a fait confianceDécider le traitement à ajouterRevenir 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
  • none et les algorithmes imprévus sont refusés
  • Signature, iss, aud, exp, nbf sont 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
Une revue essaie ce qui vient après le cas nominalAu-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.Confirmer le succès d'une requête normaleConfirmer en ne changeant que l'identifiant cibleConfirmer en ajoutant un champ de mise à jour inconnuRépéter échec d'authentification et réémissionConfirmer refus, enregistrement et récupérationTraiter 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.

Correspondance entre vulnérabilités et contre-mesuresPré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.Séparer les frontières auxquelles on fait confianceJeton et tentatives d'authentificationDonnées cibles et champs de mise à jourExécution depuis une entrée externeFixer les algorithmes autorisés et limiter les tentativesRecouper le sujet et limiter le DTO de mise à jourAtté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.

Conclusion finaleLe 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.la confirmer séparémentl'omettre parce que la précédente a réussiSuccès de la validation précédenteLa vérification suivante est-elle aussi satisfaite ?Empiler les jugements frontière par frontièreIl reste une frontière non vérifiéeLe 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

  1. 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

  2. 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

  3. 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

  4. 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

  5. RFC Editor, RFC 7519: JSON Web Token (JWT). Spécification JWT, y compris Unsecured JWT et alg=none. ↩

  6. 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. ↩

  7. 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. ↩

  8. 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. ↩

  9. 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 récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

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.

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.

Retour au blog