Objectifs
À la fin de ce cours, tu seras capable de :
- Identifier les faiblesses d'implémentation dans un flux OAuth 2.0 ou OpenID Connect (OIDC) : validation de
redirect_uri, gestion du paramètrestate, utilisation de PKCE et association de comptes. - Analyser les échanges HTTP entre le navigateur, le client OAuth (l'application) et le serveur d'autorisation pour détecter les fuites de codes d'autorisation ou de jetons.
- Démontrer une prise de contrôle de compte (ATO) ou une association abusive de profil en utilisant exclusivement tes propres comptes de test, sans impacter d'utilisateurs légitimes.
- Évaluer la sévérité CVSS 3.1 d'un défaut OAuth selon la présence de protections complémentaires (PKCE, validation stricte de l'e-mail, interaction utilisateur).
- Rédiger des recommandations de correction conformes aux meilleures pratiques actuelles (RFC 6749, RFC 9700 OAuth 2.0 Security BCP) : correspondance exacte des URI de redirection,
stateimprédictible lié à la session, etcode_challengeS256 obligatoire.
Pourquoi c'est important en bug bounty
OAuth 2.0 est devenu le standard de fait pour l'authentification déléguée et le Single Sign-On (SSO) sur le web et le mobile : « Se connecter avec Google », « Se connecter avec GitHub », ou la délégation d'accès entre microservices et applications tierces. Pourtant, bien que les RFC soient rigoureuses, la complexité de leur mise en œuvre par les développeurs conduit très fréquemment à des failles de logique majeures.
Dans les programmes de bug bounty, les vulnérabilités OAuth sont particulièrement convoitées pour plusieurs raisons :
- Impact critique direct : une faille sur la validation de
redirect_uriou sur la gestion dustatepermet souvent une prise de contrôle de compte (Account Takeover, ATO) totale, immédiate et silencieuse. - Vulnérabilités de logique invisibles aux scanners : aucun scanner automatisé générique ne comprend les subtilités d'un flux multi-rôles asynchrone nécessitant l'interaction de deux sessions distinctes. Seule une analyse manuelle minutieuse permet d'identifier ces brèches.
- Paiements élevés : sur les plateformes comme HackerOne, Bugcrowd ou YesWeHack, un rapport démontrant une prise de compte complète via OAuth 2.0 est quasi systématiquement classé en sévérité Critique ou Élevée (High), avec les primes maximales associées.
Ce qui fait la différence entre un rapport payé et un rapport fermé sans suite (« Informative » ou « Duplicate ») :
- L'exactitude de la démonstration : montrer qu'un code d'autorisation peut être volé ou qu'un compte peut être rattaché de force à la session d'un tiers, plutôt que de simplement signaler « le paramètre state est absent ».
- Le respect de l'éthique : réaliser la preuve de concept (PoC) avec deux comptes appartenant au chercheur, sans jamais intercepter de code ou de jeton appartenant à un utilisateur réel du service.
Le mécanisme
Le protocole OAuth 2.0 (RFC 6749) et son extension d'identité OpenID Connect (OIDC) reposent sur la séparation de quatre rôles distincts :
- Le propriétaire de la ressource (l'utilisateur qui utilise son navigateur).
- Le client (l'application web ou mobile qui sollicite l'accès, par exemple
app.acme.test). - Le serveur d'autorisation (l'entité qui authentifie l'utilisateur et émet les jetons, par exemple
id.exemple.fr). - Le serveur de ressources (l'API qui héberge les données protégées, par exemple
api.exemple.fr).
Dans le flux le plus robuste et le plus répandu — le flux avec Code d'autorisation (Authorization Code Flow) complété par PKCE (Proof Key for Code Exchange, RFC 7636) —, l'application ne reçoit jamais directement le mot de passe de l'utilisateur.
Les trois maillons critiques de la chaîne
Pour comprendre où les failles apparaissent, il faut examiner les trois mécanismes fondamentaux garantissant la sécurité du flux :
1. La validation du redirect_uri (Étape 2 & 5)
Lorsqu'un utilisateur clique sur « Se connecter », le client génère une URL de redirection vers le serveur d'autorisation. Le paramètre redirect_uri indique au serveur d'autorisation où renvoyer le code temporaire après le consentement de l'utilisateur.
Si le serveur d'autorisation valide mal cette URI (comparaison par préfixe lâche, acceptation de jokers *, omission du chemin, ou acceptation de sous-domaines arbitraires), un attaquant peut manipuler le lien pour que le code d'autorisation soit transmis vers un serveur sous son contrôle ou vers une page vulnérable à une redirection ouverte (Open Redirect).
2. Le paramètre state et la prévention du CSRF de login (Étape 2 & 5)
Le paramètre state est une valeur pseudo-aléatoire, imprédictible et cryptographiquement forte, générée par le client et stockée dans la session du navigateur de l'utilisateur au moment où il initie la demande de connexion. Lorsque le serveur d'autorisation redirige le navigateur vers le client avec le code, il renvoie exactement la même valeur de state.
Le client doit alors vérifier que le state reçu correspond rigoureusement à celui stocké dans la session locale de l'utilisateur.
- Si le
stateest absent, non vérifié, ou prédictible, un attaquant peut intercepter son propre code d'autorisation valide et faire consommer ce code par le navigateur de la victime via une requête CSRF. La session de la victime surapp.acme.testse retrouve alors liée au compte d'authentification de l'attaquant (Login CSRF).
3. PKCE : Proof Key for Code Exchange (Étape 2 & 6)
Initialement conçu pour les clients mobiles et les Single Page Applications (SPA) ne pouvant pas stocker de secret client de manière confidentielle, PKCE est désormais recommandé par la RFC 9700 pour tous les clients OAuth, y compris les applications serveur traditionnelles.
- Le client génère un secret temporaire à usage unique : le
code_verifier. - Il en calcule l'empreinte cryptographique SHA-256 : le
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier)). - Il transmet le
code_challengeau serveur d'autorisation lors de la requête initiale. - Lors de l'échange final du code temporaire contre les jetons (étape 6, requête directe de serveur à serveur), le client transmet le
code_verifieren clair. - Le serveur d'autorisation recalcule le SHA-256 du
code_verifieret s'assure qu'il concorde avec lecode_challengeenregistré. Même si un tiers parvient à voler le code d'autorisation dans le navigateur ou les journaux, il est incapable de l'échanger sans posséder lecode_verifier.
Où chercher
La surface d'attaque OAuth s'étend à chaque étape du cycle de vie de la fédération d'identité. Lors de l'exploration d'une cible, examine attentivement les fonctionnalités suivantes :
1. Boutons d'authentification sociale et SSO
Toutes les pages de connexion proposant des fournisseurs tiers (Google, Microsoft, GitHub, Apple, Facebook, Okta, Keycloak). Analyse la requête initiée au clic :
GET /oauth/authorize?
response_type=code
&client_id=acme_web_app_99182
&redirect_uri=https%3A%2F%2Fapp.acme.test%2Fauth%2Fcallback
&scope=openid%20profile%20email
&state=8f7b2c9e10a44d
&code_challenge=E9Melhoa2OwvFrGMTJguCH5rtx64fZqiJ405nmSX-la
&code_challenge_method=S256 HTTP/1.1
Host: id.exemple.fr2. Fonctionnalités de liaison de compte dans les paramètres de profil
Dans les réglages de l'utilisateur (/account/security ou /settings/integrations), lorsqu'une application permet de « Lier son compte Google » ou « Connecter son compte GitHub ». Ces flux omettent encore plus fréquemment la vérification du state que le flux de connexion principal, permettant d'associer le compte tiers de l'attaquant au profil de la victime.
3. Applications mobiles et clients lourds
Les applications mobiles utilisent souvent des schémas d'URI personnalisés (Custom URL Schemes, par exemple acmeapp://oauth/callback). Si le système d'exploitation permet à plusieurs applications d'enregistrer le même schéma d'URI sans vérification de domaine (Android Intent ou iOS Universal Links mal configurés), un composant malveillant peut intercepter les redirections.
Question de réflexion : Pourquoi le flux implicite (Implicit Flow) est-il formellement déprécié ?
Dans le flux implicite (response_type=token), le serveur d'autorisation renvoie directement le jeton d'accès (access_token) dans le fragment d'URL (#access_token=...) de la redirection, sans passer par un code intermédiaire ni par une requête serveur à serveur. Ce fonctionnement expose directement le jeton au navigateur : il apparaît dans l'historique de navigation, peut fuiter via l'en-tête Referer vers des ressources tierces chargées sur la page de rappel, et est accessible à tout script malveillant présent dans la page. La spécification RFC 9700 (OAuth 2.0 Security Best Current Practice) interdit désormais formellement l'utilisation de l'Implicit Flow au profit du flux Authorization Code avec PKCE.
Méthode de test
Une approche méthodique et rigoureuse est indispensable pour évaluer les intégrations OAuth. Suis cette démarche étape par étape à l'aide d'un proxy d'interception (tel que Caido, Burp Suite ou ZAP).
Étape 1 : Cartographie de la requête d'autorisation
Intercepte la première requête GET vers le serveur d'autorisation (/oauth/authorize). Note et analyse chaque paramètre :
- Le
response_typevaut-il biencode? (Sitokenest accepté, l'application supporte le flux implicite déprécié). - Le paramètre
stateest-il présent ? Sa valeur change-t-elle à chaque tentative ? Est-elle suffisamment longue et entropique ? - Les paramètres
code_challengeetcode_challenge_method=S256sont-ils présents ?
Étape 2 : Test de validation du redirect_uri
C'est le test le plus important pour identifier une fuite de code d'autorisation. Modifie le paramètre redirect_uri dans la requête d'autorisation vers id.exemple.fr et observe la réaction du serveur :
-
Test de correspondance exacte :
- Original :
https://app.acme.test/auth/callback - Test :
https://app.acme.test/auth/callback/testouhttps://app.acme.test/auth - Si le serveur accepte la redirection sans lever d'erreur
invalid_requestouredirect_uri_mismatch, l'URI n'est pas vérifiée par correspondance exacte.
- Original :
-
Test de traversée de chemin (Directory Traversal) :
- Test :
https://app.acme.test/auth/callback/../../open-redirect - Si le serveur normalise le chemin ou le transmet tel quel à un endpoint vulnérable de l'application cliente, le code sera redirigé.
- Test :
-
Test de manipulation de sous-domaine / contournement de domaine :
- Test :
https://evil.acme.test/auth/callback(sous-domaine arbitraire) - Test :
https://app.acme.test.evil.exemple.fr/auth/callback(domaine suffixé) - Test :
https://app.acme.test@evil.exemple.fr/auth/callback(utilisation de syntaxe d'authentification URL)
- Test :
GET /oauth/authorize?
response_type=code
&client_id=acme_web_app_99182
&redirect_uri=https%3A%2F%2Fapp.acme.test%2Fstatic%2Fanalytics.html
&state=12345 HTTP/1.1
Host: id.exemple.frSi le serveur d'autorisation accepte une page statique ou une redirection ouverte hébergée sur app.acme.test, le code peut être intercepté via les scripts de cette page ou l'en-tête Referer.
Étape 3 : Test de robustesse du paramètre state
Pour tester la présence de vulnérabilités CSRF de login ou d'association de compte :
- Démarre un flux de connexion avec ton compte de test A sur un navigateur configuré avec un proxy.
- Autorise l'accès sur le serveur d'autorisation.
- Intercepte et bloque la redirection finale vers le client :
GET /auth/callback?code=AUTH_CODE_ACCOUNT_A&state=ORIGINAL_STATE HTTP/1.1 Host: app.acme.test - Copie cette URL complète.
- Dans un second navigateur indépendant (ou une session privée simulant la victime, ton compte de test B déjà connecté), colle et exécute l'URL de rappel.
- Analyse le résultat :
- Comportement sécurisé : l'application rejette la requête car le
statene correspond pas à la session du navigateur B, ou le jeton de session lié austateest manquant. - Comportement vulnérable : l'application accepte le code et associe ou connecte le compte A dans la session du compte B.
- Comportement sécurisé : l'application rejette la requête car le
Étape 4 : Test de dissociation et réutilisation du code
Le protocole impose que le code d'autorisation soit à usage unique et possède une durée de vie très courte (inférieure à 10 minutes, idéalement 60 secondes).
- Capture une requête POST légitime d'échange de code :
POST /oauth/token HTTP/1.1 Host: id.exemple.fr Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=SPL_CODE_987123 &redirect_uri=https%3A%2F%2Fapp.acme.test%2Fauth%2Fcallback &client_id=acme_web_app_99182 &code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk - Renvoie immédiatement la même requête. Le serveur doit renvoyer une erreur
invalid_grantet invalider immédiatement tous les jetons éventuellement déjà émis à partir de ce code (RFC 6749, section 4.1.2).
Variantes et défenses courantes
1. Fuite du code d'autorisation via l'en-tête Referer
Lorsqu'un code d'autorisation est délivré à l'application cliente sur l'URI /auth/callback?code=SECRET_CODE, si cette page charge des ressources tierces (scripts publicitaires, outils de mesure d'audience, polices externes, iframes) ou propose des liens externes sur lesquels l'utilisateur clique immédiatement, le navigateur envoie l'URL courante dans l'en-tête HTTP Referer.
L'attaquant qui administre le domaine externe reçoit le code d'autorisation en clair dans ses journaux de serveur web.
2. Prise de contrôle par pré-création de compte ou e-mail non vérifié
Cette variante subtile concerne la logique métier lors de la réception des informations d'identité :
- L'attaquant crée un compte sur l'application cible avec l'e-mail de la victime (
victime@exemple.fr) via le formulaire classique (mot de passe local), ou via un fournisseur d'identité tiers qui ne vérifie pas la possession de l'e-mail. - Plus tard, la victime clique sur « Se connecter avec Google » avec son compte légitime
victime@exemple.fr. - Si l'application associe automatiquement le compte sans vérifier que l'e-mail du compte préexistant avait été confirmé par un lien d'activation, l'attaquant (qui connaît le mot de passe local défini lors de la pré-création) conserve un accès permanent au compte de la victime, même après la liaison SSO.
Question de réflexion : Comment PKCE protège-t-il contre l'interception de code même si un attaquant vole le code via le Referer ?
Si le client applique PKCE avec la méthode S256, le serveur d'autorisation associe le code émis au code_challenge transmis lors de l'étape 1. Pour échanger ce code contre un jeton d'accès, l'attaquant devrait envoyer le code_verifier original dans sa requête POST /oauth/token. Or, ce code_verifier est resté confiné dans la mémoire ou la session sécurisée du client légitime de la victime : il n'a jamais transité dans l'URL ni dans l'en-tête Referer. Sans ce secret, le code d'autorisation volé est totalement inutilisable par l'attaquant.
Prouver l'impact sans nuire
La règle d'or en bug bounty sur les flux d'authentification est la maîtrise absolue de l'environnement de test. Tout rapport démontrant une vulnérabilité OAuth doit respecter scrupuleusement les exigences suivantes :
Ce que les programmes acceptent et valorisent
- Preuve à deux comptes de test : crée deux comptes que tu possèdes personnellement (par exemple
hunter-test-1@exemple.frethunter-test-2@exemple.fr). Démontre que tu peux lier le profil social du compte 1 au compte 2, ou te connecter sur la session du compte 2 sans son mot de passe. - Démonstration de redirection non destructive : si tu découvres un contournement de
redirect_uri, utilise un paramètre pointant vers un domaine d'observation autorisé ou une page inoffensive du domaine cible (par exemplehttps://app.acme.test/robots.txt), en montrant la présence du paramètre?code=...dans la requête redirigée. - Arrêt immédiat à la preuve minimale : dès que tu obtiens le code d'autorisation sur ton endpoint de test ou que tu constates l'échange réussi entre tes deux comptes, arrête tes investigations. Tu as prouvé l'ATO, inutile de télécharger les données du profil ou de manipuler les fonctionnalités du compte.
Ce qui est strictement interdit
- Ne teste jamais de vol de code ou de manipulation de compte sur un utilisateur réel ou un compte administrateur du programme.
- N'exfiltre pas de jetons de production ni d'informations confidentielles associées aux comptes d'autres utilisateurs.
- Ne modifie pas les paramètres d'autorisation d'autres utilisateurs pour tenter de verrouiller leur accès.
Évaluer la sévérité
Le tableau suivant présente quatre scénarios types de vulnérabilités OAuth avec leur scoring CVSS v3.1 calculé rigoureusement selon la spécification FIRST :
| Scénario de vulnérabilité | Vecteur CVSS 3.1 | Score de base | Sévérité | Justification |
|---|---|---|---|---|
Vol de code via contournement de redirect_uri sans PKCE (ATO complète) | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H | 8.8 | High | L'attaquant incite la victime à cliquer sur un lien malveillant (UI:R), le code d'autorisation fuit vers son serveur, permettant une prise de contrôle totale du compte sans privilège préalable (PR:N). |
CSRF de connexion via omission du paramètre state (Login CSRF) | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N | 4.3 | Medium | L'attaquant force la victime à se connecter sur le compte de l'attaquant. Si la victime saisit des données personnelles ou effectue des achats, l'attaquant peut les consulter ultérieurement, mais il n'y a pas d'accès direct aux données existantes de la victime. |
Liaison de compte tiers sans vérification de state (Account Hijack) | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H | 8.8 | High | L'attaquant transmet un lien qui lie son propre profil tiers au compte connecté de la victime. Une fois l'association effectuée, l'attaquant peut se connecter à tout moment au compte de la victime via le bouton SSO. |
| Association de compte sur e-mail non vérifié chez le fournisseur SSO | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H | 8.1 | High | L'attaquant enregistre un compte sur un fournisseur d'identité n'imposant pas la vérification de l'e-mail avec l'adresse d'une victime, puis s'authentifie sur l'application cible qui effectue une fusion aveugle sans interaction (UI:N, complexité plus élevée AC:H). |
Corriger
La remédiation d'une implémentation OAuth défaillante nécessite d'agir à la fois côté serveur d'autorisation et côté application cliente.
Exemple en Node.js / Express : implémentation sécurisée du rappel OAuth
Code vulnérable (absence de validation de state et absence de PKCE)
// MAUVAISE PRATIQUE : vulnérable au CSRF de login et à la manipulation de session
app.get('/auth/callback', async (req, res) => {
const { code } = req.query;
if (!code) {
return res.status(400).send('Code manquant');
}
// Échange direct du code sans vérifier de state ni de code_verifier
const tokenResponse = await fetch('https://id.exemple.fr/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
client_id: process.env.OAUTH_CLIENT_ID,
client_secret: process.env.OAUTH_CLIENT_SECRET,
redirect_uri: 'https://app.acme.test/auth/callback',
}),
});
const tokens = await tokenResponse.json();
const userProfile = await fetchProfile(tokens.access_token);
// Authentification de la session locale sans validation du demandeur initial
req.session.userId = userProfile.id;
res.redirect('/dashboard');
});Code corrigé (vérification stricte du state et utilisation de PKCE)
import crypto from 'node:crypto';
// 1. Initialisation de la demande d'authentification
app.get('/auth/login', (req, res) => {
// Génération d'un state aléatoire cryptographique
const state = crypto.randomBytes(32).toString('hex');
// Génération des composants PKCE (RFC 7636)
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
// Stockage strict dans la session HTTP sécurisée
req.session.oauthState = state;
req.session.oauthCodeVerifier = codeVerifier;
const authUrl = new URL('https://id.exemple.fr/oauth/authorize');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', process.env.OAUTH_CLIENT_ID);
authUrl.searchParams.set('redirect_uri', 'https://app.acme.test/auth/callback');
authUrl.searchParams.set('scope', 'openid profile email');
authUrl.searchParams.set('state', state);
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
res.redirect(authUrl.toString());
});
// 2. Traitement sécurisé du retour d'autorisation
app.get('/auth/callback', async (req, res) => {
const { code, state } = req.query;
const savedState = req.session.oauthState;
const codeVerifier = req.session.oauthCodeVerifier;
// Nettoyage immédiat de la session pour empêcher toute réutilisation
delete req.session.oauthState;
delete req.session.oauthCodeVerifier;
// Validation cryptographique du state (atténue le CSRF)
if (!state || !savedState || state !== savedState) {
return res.status(403).send('Échec de vérification du state : requête non autorisée');
}
if (!code || !codeVerifier) {
return res.status(400).send('Paramètres d’autorisation invalides');
}
// Échange du code avec validation du code_verifier PKCE
const tokenResponse = await fetch('https://id.exemple.fr/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: String(code),
client_id: process.env.OAUTH_CLIENT_ID,
client_secret: process.env.OAUTH_CLIENT_SECRET,
redirect_uri: 'https://app.acme.test/auth/callback',
code_verifier: codeVerifier,
}),
});
if (!tokenResponse.ok) {
return res.status(401).send('Échec de validation du code d’autorisation');
}
const tokens = await tokenResponse.json();
const userProfile = await fetchProfile(tokens.access_token);
// Régénération impérative de l'identifiant de session (lutte contre la fixation)
req.session.regenerate((err) => {
if (err) return res.status(500).send('Erreur interne de session');
req.session.userId = userProfile.id;
res.redirect('/dashboard');
});
});Principes de défense en profondeur
- Correspondance exacte des URI de redirection : configurer le serveur d'autorisation pour exiger une correspondance stricte de chaîne de caractères (
exact string matching) sur lesredirect_urienregistrés. Ne jamais autoriser d'expressions régulières permissives ou de jokers (*). - Utilisation universelle de PKCE : appliquer PKCE systématiquement avec
code_challenge_method=S256pour tous les flux, qu'ils proviennent d'applications mobiles, de clients SPA ou d'applications backend. - Protection contre les fuites Referer : définir l'en-tête HTTP
Referrer-Policy: no-referrersur l'ensemble des pages de rappel d'authentification pour interdire l'exposition du code dans les en-têtes des requêtes sortantes. - Vérification de l'e-mail avant liaison : lors de la connexion SSO, ne fusionner automatiquement deux comptes sur la base de leur adresse e-mail que si le champ
email_verified: trueest explicitement retourné et signé par le fournisseur d'identité dans l'ID Token.
Erreurs qui font rejeter un rapport
- Signaler l'absence de
statesans démontrer de CSRF fonctionnel : si l'application cliente utilise PKCE de manière stricte avec uncode_verifierstocké dans un cookieHttpOnly, l'absence de paramètrestatene permet pas d'échanger le code d'un tiers. Démontre l'impact réel avant de soumettre. - Tester sur des domaines tiers hors scope : lors d'un flux OAuth, l'utilisateur est redirigé vers Google, Microsoft ou GitHub. Les vulnérabilités éventuelles de ces géants du web sont hors du périmètre du programme audité. Ton analyse doit porter exclusivement sur la configuration de l'application cliente et sur les serveurs d'autorisation gérés par le programme.
- Confondre un ID Token public avec un jeton d'accès secret : dans OpenID Connect, l'ID Token est un JWT conçu pour être lu par le client. Découvrir qu'un utilisateur peut décoder son propre ID Token dans son navigateur n'est en aucun cas une vulnérabilité.
- Prétendre à une ATO sans démontrer le vol du code : affirmer qu'un
redirect_uriest vulnérable sans fournir d'URL fonctionnelle redirigeant effectivement le paramètrecodevers un domaine tiers ou sans contourner les filtres en place. - Rapports générés par des scanners automatisés : les signalements génériques mentionnant « OAuth misconfigure » sans requêtes HTTP détaillées ni comptes de test sont systématiquement classés comme « Not Applicable ».
Checklist du hunter
Avant de clôturer tes tests sur une implémentation OAuth 2.0, vérifie systématiquement :
- La requête
/authorizeutilise-t-elle le fluxcodeplutôt que le flux implicitetoken? - Le paramètre
stateest-il présent, imprédictible et vérifié lors du rappel/callback? - L'URI de redirection
redirect_uriest-elle soumise à une correspondance exacte (test des chemins, sous-domaines, caractères spéciaux) ? - Le protocole PKCE est-il requis avec la méthode
S256? - Le code d'autorisation expire-t-il rapidement (moins de 60 secondes) et est-il strictement à usage unique ?
- Les pages de rappel intègrent-elles la directive
Referrer-Policy: no-referrer? - L'association de compte dans les paramètres de profil requiert-elle une validation CSRF distincte ?
- L'application refuse-t-elle de fusionner des comptes si l'e-mail fourni par le SSO n'est pas vérifié ?
Pour aller plus loin
- RFC 6749 : The OAuth 2.0 Authorization Framework — Le standard fondamental définissant les rôles, les types d'autorisations et les profils de clients.
- RFC 7636 : Proof Key for Code Exchange by OAuth Public Clients (PKCE) — La spécification technique détaillant le mécanisme de protection par défi cryptographique.
- RFC 9700 : OAuth 2.0 Security Best Current Practice — La référence contemporaine d'architecture sécurisée actualisant les recommandations de la RFC 6749 et dépréciant les pratiques obsolètes.
- OWASP Web Security Testing Guide (WSTG v4.2) : Testing for OAuth 2.0 Vulnerabilities (WSTG-ATHN-05) — Méthodologie pratique d'audit des flux OAuth et OIDC.
- PortSwigger Web Security Academy : OAuth 2.0 authentication vulnerabilities — Laboratoires interactifs et analyses détaillées des attaques sur les flux d'autorisation.