Les mots de passe ont vĂ©cu, vive le passwordless đ€ â mais pas encore totalement enterrĂ©s. Entre rĂ©utilisation, phishing, fuites massives et usagers fatiguĂ©s, la gestion des identifiants est devenue la premiĂšre cause opĂ©rationnelle de compromission. Sans compter les MFA Fatigue : ou comment cliquer frĂ©nĂ©tiquement sur âAccepterâ est devenu la nouvelle faille. Câest dans ce contexte que les passkeys émergent : une façon dâauthentifier un utilisateur sans jamais transmettre ni stocker un secret rĂ©utilisable cĂŽtĂ© serveur, grĂące Ă la cryptographie Ă clĂ© publique. Les gĂ©ants et la communautĂ© standards poussent fort (FIDO, W3C/WebAuthn) : lâidĂ©e est simple sur le papier et sĂ©duisante en pratique â moins dâemails « mot de passe oubliĂ© », moins de phishing rĂ©ussi, moins de tickets helpdesk. FIDO Alliance
Mais attention : « sans mot de passe » ne veut pas dire « sans risques ». Le passage de la thĂ©orie (clĂ© publique/privĂ©e) Ă la production dans des environnements hĂ©tĂ©rogĂšnes (desktop + mobile + applis legacy + reverse proxies + SSO fĂ©dĂ©rĂ©) introduit toute une sĂ©rie de surfaces dâattaque et de piĂšges opĂ©rationnels. On y revient plus bas, avec des scĂ©narios concrets.
- đ§© Quâest-ce quâune passkey ?
- đ Principe PKI & challenge-response (explication accessible, sans Diffie-Hellman)
- â Les 19 points de validation WebAuthn (registration)
- đ§š ScĂ©nario dâattaque â compromission dâun magasin de certificats (attestation)
- đđȘ WebAuthn & navigateurs â pourquoi le client web reste le maillon fragile
- đ Extensions malveillantes et profils compromis
- đ§Ż WebUSB, WebHID, WebBluetooth â trop de portes ouvertes
- âïž XSS + WebAuthn = mauvais mĂ©lange
- đ Attaques de relay / clickjacking & user gestures
- đ§ La confiance dans le navigateur â et pourquoi câest un problĂšme dâinfra
- â Recommandations de base cĂŽtĂ© produit & infra
- đïž Le problĂšme de fond : lâentreprise nâest pas Google
- 1. Active Directory & Azure AD
- 2. ERP & applis legacy
- 3. VPN & accÚs réseau
- đ§° Bonnes pratiques dâimplĂ©mentation (sans paillettes)
- đ€š Conclusion â « Tâes vraiment sĂ»r, on y va ? »
- ANNEXES
- Playbook IR : Compromission du magasin dâattestation (PKI / CA / FIDO metadata)
- 1) Activation & premiĂšres minutes (0â60 min)
- 2) Investigation rapide (60â240 min)
- 3) Containment (4â24 h)
- 4) Eradication & remediation (24hâ7 jours)
- 5) Recovery & re-enrollment (J+3 â J+30)
- 6) Communication â templates (rapide & efficace)
- 7) Monitoring & détection post-incident (alerts à déployer)
- 8) RÎles & responsabilités (RACI bref)
- 9) Post-mortem & actions long terme (30â90 jours)
- Conclusion â la morale amĂšre
- đ Cadeau : script PowerShell pour dĂ©tecter et lister certificats racine rĂ©cemment installĂ©s sur un parc.
- Playbook IR : Compromission du magasin dâattestation (PKI / CA / FIDO metadata)
đ§© Quâest-ce quâune passkey ?
Une passkey est, pour faire vite, un type de credential (identifiant cryptographique) basé sur le modÚle clé publique / clé privée. ConcrÚtement :
- Lâappareil de lâutilisateur crĂ©e localement une paire de clĂ©s.
- La clé publique est envoyée et stockée sur le serveur du service (le « relying party »).
- La clĂ© privĂ©e reste sur lâappareil (smartphone, PC, clĂ© matĂ©rielle). Elle ne sort jamais.
Lors de lâauthentification, le serveur envoie un challenge (un petit paquet unique) que lâappareil signe avec la clĂ© privĂ©e. Le serveur vĂ©rifie la signature avec la clĂ© publique quâil a stockĂ©e. Si la signature colle, lâutilisateur est authentifiĂ© â sans mot de passe Ă taper, et sans secret cĂŽtĂ© serveur pouvant ĂȘtre rĂ©utilisĂ© sur dâautres sites. Ce mĂ©canisme est la base de WebAuthn/FIDO.
đ Principe PKI & challenge-response (explication accessible, sans Diffie-Hellman)
On va le dire simplement, étape par étape (pour un novice technique) :
- Enregistrement (inscription)
- Lâutilisateur clique « Enregistrer un passkey ». Sa machine gĂ©nĂšre une paire de clĂ©s (privĂ©e + publique).
- La clĂ© publique est envoyĂ©e au serveur, avec des mĂ©tadonnĂ©es (type dâauthenticator, attestation si disponible). Le serveur stocke la clĂ© publique associĂ©e Ă lâutilisateur.
- Authentification (login)
- Le serveur gĂ©nĂšre un challenge (nombre alĂ©atoire unique) et lâenvoie au client.
- Le client demande Ă lâauthenticator local (puce TPM / enclave/clĂ© USB) de signer ce challenge avec la clĂ© privĂ©e. Lâutilisateur valide localement (PIN ou biomĂ©trie).
- Le client renvoie la signature au serveur. Le serveur vĂ©rifie la signature avec la clĂ© publique stockĂ©e. Si OK â accĂšs accordĂ©.
Pourquoi câest fort : la clĂ© privĂ©e ne transite jamais, elle nâest pas copiable (sauf si lâappareil est compromis ou si lâauthenticator le permet). MĂȘme si un pirate vole la base de donnĂ©es du serveur, il nâobtient que des clĂ©s publiques â inutile pour se faire passer pour lâutilisateur. passkeycentral.org
đ FIDO / WebAuthn â ce que les devs doivent vraiment savoir
WebAuthn (la couche standardisĂ©e cĂŽtĂ© web) + FIDO (les specs dâauthenticators) forment la brique qui rend les passkeys utilisables par les navigateurs et les systĂšmes. Câest beau sur le papier : un navigateur parle Ă lâauthenticator (TPM, secure enclave, clĂ© USB), lâauthenticator signe un challenge, et le serveur vĂ©rifie la signature. Mais pour quâun dĂ©ploiement soit sĂ»r, le serveur doit faire un tas de vĂ©rifications â pas juste âvĂ©rifier la signatureâ et hop. La spec dĂ©finit une procĂ©dure dĂ©taillĂ©e (la fameuse procĂ©dure en ~19 points pour la validation dâenregistrement) que tout dev sĂ©rieux doit implĂ©menter ou dĂ©lĂ©guer Ă une librairie fiable.
đ§Ÿ Le flux dâimplĂ©mentation cĂŽtĂ© serveur (vue pragmatique)
1) Inscription (registration) â checklist serveur
Lorsquâun client envoie la PublicKeyCredential
aprĂšs navigator.credentials.create()
, cÎté serveur il faut valider scrupuleusement :
- Vérifier que le RP ID (relying party id) correspond bien à votre domaine / scope attendu.
- VĂ©rifier lâorigin dans leÂ
clientDataJSON
 (mĂȘme hĂŽte + protocol) : câest la barriĂšre anti-phishing cĂŽtĂ© web. - VĂ©rifier que le challenge retournĂ© est bien celui que le serveur a Ă©mis (liĂ© Ă la session utilisateur).
- ParserÂ
attestationObject
 (CBOR), extraireÂauthenticatorData
 et la clĂ© publique (COSE format) â attention au dĂ©codage base64url / CBOR. - VĂ©rifier le format dâattestation (
fmt
) et valider lâattestation en consĂ©quence (packed, tpm, fido-u2f, android-key, android-safetynet, apple, none). Selon le format, il faudra vĂ©rifier des certificats, signer des chaĂźnes, ou accepter lâabsence dâattestation. - ContrĂŽler le signatureCounter initial (doit exister) et enregistrer la clĂ© publique + credential ID + counter + algorithme.
- Respecter la politique dâattestation choisie : accepter les attestations « none » (anonymes) ou exiger une attestation vĂ©rifiable via la FIDO Metadata Service.
- Valider flagsÂ
uv
 (user verification) /Âup
 (user presence) selon votre requirement (MFA, passwordless strict, etc.). - GĂ©rer erreurs et rejets : logging, rĂ©ponse claire pour lâUX cĂŽtĂ© client.
Ces Ă©tapes sont celles formalisĂ©es dans le spec â ne pas les faire, câest sâexposer Ă des contournements. Google for Developers+1
đ Attestation : utile mais dangereux â et pourquoi tu dois dĂ©cider dâune politique
Lâattestation est la preuve que lâauthenticator est bien fabriquĂ© par un fournisseur (attestation certificate chain). Câest utile pour dĂ©tecter des authenticators compromis ou non-conformes, mais :
- Les formats sont variĂ©s :Â
packed
,Âtpm
,Âfido-u2f
,Âandroid-key
,Âandroid-safetynet
,Âapple
,Ânone
. Chacun a une vĂ©rification diffĂ©rente. MDN Web Docs - Exiger lâattestation « full trust » (chaĂźne CA vĂ©rifiĂ©e) augmente la sĂ©curitĂ©, mais rĂ©duit lâinteropĂ©rabilitĂ© (beaucoup dâauthenticators vont renvoyerÂ
none
 ouÂpacked
 sans chaĂźne publiquement vĂ©rifiable). - Il existe des services et listes (FIDO Metadata Service) pour vĂ©rifier les identifiants dâauthenticators. Pour les environnements sensibles, activer la vĂ©rification metadata est recommandĂ© ; en revanche, câest une gestion opĂ©rationnelle en plus.
Bref : dĂ©cide si tu veux contrĂŽler le modĂšle dâauthenticator, ou faire confiance au device & UX. Les deux approches ont un coĂ»t. W3C
â VĂ©rification dâassertion (login) â les checks impĂ©ratifs
Lors dâun login (assertion), le serveur doit :
- RĂ©cupĂ©rer leÂ
credentialId
 envoyĂ© et retrouver la clĂ© publique + counter associĂ©e. - VĂ©rifier que lâorigin et le rpId matchent.
- VĂ©rifier que le challenge dansÂ
clientDataJSON
 correspond Ă celui Ă©mis par le serveur. - VĂ©rifier la signature de lâ
authenticatorData || clientDataHash
 avec la clĂ© publique (algorithme COSE attendu). - VĂ©rifier les flagsÂ
up
 (user presence) etÂuv
 (user verification) selon la politique de lâapp. - VĂ©rifier que la signatureCounter est bien supĂ©rieure au compteur stockĂ© (dĂ©tection de clones/devices clonĂ©s). Si non â alerter / rĂ©voquer.
- Mettre à jour le compteur stocké.
- Rejeter si quoi que ce soit ne colle (mauvais algorithme, challenge mismatch, signature invalide, rpId mismatch, origin mismatch).
Ces Ă©tapes (et dâautres variantes) sont listĂ©es par la spec et implĂ©mentĂ©es par des bibliothĂšques matures (Duo Labs, Yubico, SimpleWebAuthn, WebAuthn4J, etc.). DĂ©lĂ©guer Ă une librairie testĂ©e rĂ©duit drastiquement les piĂšges.
𧩠Les piÚges techniques qui vont te pourrir la vie (et comment les éviter)
- CBOR / COSE parsing : erreurs de parsing = vulnérabilité. Utiliser des libs éprouvées.
- Origin vs RP ID : si tu te trompes, tu acceptes des assertions depuis dâautres domaines (phishing). Toujours vĂ©rifier strictement lâorigin.
- Algorithmes supportĂ©s : nâaccepte pas aveuglĂ©ment toutes les clefs/algos ; impose ECDSA P-256 (ES256) ou Ă©quivalents robustes.
- Gestion du credentialId : doit ĂȘtre indexable et unique â attention aux collisions et formats (binary blob).
- Compteurs : les authenticators logiciels peuvent ne pas incrĂ©menter correctement â politique de tolĂ©rance Ă prĂ©voir mais aussi processus dâinvestigation.
- Attestation CA compromise / magasin de certificats : si une CA dâattestation est compromise, tu dois pouvoir rĂ©voquer les attestations et forcer rĂ©enregistrement. (On dĂ©taille le scĂ©nario magasin de certificats dans la section attaque.) developers.yubico.com
đ§Ÿ Le â19 pointsâ â que faut-il retenir ?
Le WebAuthn spec dĂ©crit une procĂ©dure en ~19 points pour valider lâenregistrement (registration) afin dâĂ©viter que lâimplĂ©mentation fasse un raccourci dĂ©lĂ©tĂšre. Ce nâest pas une check-list marketing : câest la garantie que lâon nâa pas laissĂ© une faille triviale (mismatch origin, challenge, parsing CBOR, algos, attestation, flagsâŠ). Si tu veux ĂȘtre tranquille, implĂ©mente la procĂ©dure complĂšte ou utilise une librairie qui la suit Ă la lettre â lâĂ©cosystĂšme a dĂ©jĂ des implĂ©mentations robustes (Duo Labs, Yubico, SimpleWebAuthn, WebAuthn4J). Guide to Web Authentication
â Les 19 points de validation WebAuthn (registration)
- Recevoir la rĂ©ponse client :Â
clientDataJSON
 +ÂattestationObject
. - VĂ©rifier la structure : sâassurer queÂ
clientDataJSON
 est bien JSON et queÂattestationObject
 est un CBOR valide. - ExtraireÂ
clientData
 et vĂ©rifier :- queÂ
type
 =Â"webauthn.create"
. - que le challenge correspond à celui généré par le serveur.
- que lâorigin est bien celui attendu (ex.Â
https://tondomaine.com
). - queÂ
tokenBinding
 (si présent) est cohérent.
- queÂ
- HacherÂ
clientDataJSON
 pour obtenirÂclientDataHash
. - ExtraireÂ
authenticatorData
 de lâattestationObject
. - VĂ©rifier le RP ID hash dansÂ
authenticatorData
 correspond au hash SHA-256 du RP ID attendu (ton domaine). - VĂ©rifier les flags dansÂ
authenticatorData
 :UP
 (user present) = 1 (lâutilisateur a interagi).UV
 (user verified) selon ta politique (PIN, biométrie).
- Extraire le compteur (
signCount
). - Extraire la clĂ© publique duÂ
attestedCredentialData
 (format COSE). - VĂ©rifier que leÂ
credentialId
 est unique (non déjà enregistré dans ta base). - Vérifier que la clé publique est dans un algorithme supporté (ex. ES256).
- VĂ©rifier lâattestation : format (
packed
,Âtpm
,Âfido-u2f
,Âandroid-key
, etc.). - Valider la signature de lâattestation : signature faite avec la clĂ© dâattestation sur (
authenticatorData
 +ÂclientDataHash
). - VĂ©rifier la chaĂźne de certificats dâattestation (si applicable).
- Vérifier les métadonnées (via FIDO Metadata Service ou politique interne) : AAGUID, algorithme, validité.
- VĂ©rifier les extensions (si prĂ©sentes) : que leur traitement est conforme et quâelles ne violent pas ta politique.
- Appliquer ta politique dâattestation : accepter ou refuser selon lâattestation (
none
, cert validé, etc.). - En cas de succÚs : stocker credentialId, clé publique, compteur initial, AAGUID, algorithme, flags, et attestation metadata.
- En cas dâĂ©chec : rejeter la crĂ©ation et loguer lâerreur pour analyse.
đ§ Recommandations pratiques (checklist courte pour devs)
- Nâignore jamaisÂ
clientDataJSON.origin
 et le RP ID. - Utilise une lib WebAuthn mature plutÎt que du code maison (par ex. WebAuthn4J, simplewebauthn, duo-labs).
- DĂ©cide ta politique dâattestation (accept/rejectÂ
none
, metadata service?). - Ne stocke que : credentialId, clĂ© publique (COSE), algorithme, signatureCounter, date dâĂ©mission, attestation metadata.
- Prends en charge la portabilité (passkey sync via vendor cloud) mais documente les risques et offre des alternatives (clés matérielles).
- Prévois un processus de récupération sécurisé (par ex. réenregistrement avec MFA humaine, ou workflows identifiés), pas un reset trivial par helpdesk.
- Ajoute du monitoring sur Ă©checs dâassertions, mismatch de counter, tentatives rĂ©pĂ©tĂ©es â ces signaux prĂ©cĂšdent souvent une attaque ciblĂ©e.
En bref (piquant mais franc)
WebAuthn/FIDO ne sont pas un gadget marketing Ă cocher. Câest une techno solide, mais exigeante cĂŽtĂ© implĂ©mentation et gouvernance. Si tu traites ça comme « un simple remplacement de mot de passe » et que tu skips la validation, lâattestation ou la gestion des origins, tu vas juste dĂ©placer la surface dâattaque â et probablement te retrouver avec des erreurs sournoises en prod. Fais-le propre, confie ça Ă des bibliothĂšques Ă©prouvĂ©es, et prĂ©pare-toi Ă gĂ©rer attestation, policies, et rĂ©cupĂ©ration utilisateurs. Le diable est dans les 19 points.Â
đ§š ScĂ©nario dâattaque â compromission dâun magasin de certificats (attestation)
đ Contexte rapide
La valeur ajoutĂ©e des passkeys/FIDO passe aussi par lâattestation : un authenticator peut fournir une preuve (certificat dâattestation) liant la clĂ© publique créée Ă un fabricant/produit. Les serveurs peuvent utiliser ces attestations pour dĂ©cider sâils acceptent ou non un authenticator. Mais si le magasin de certificats dâattestation (la chaĂźne de confiance, ou la PKI qui signe les attestations) est compromis â ou si un CA/Issuer est frauduleusement Ă©mis â on transfĂšre la confiance vers un composant qui peut ĂȘtre trahi. Bref : on a dĂ©placĂ© la cible.
đŻ Objectif de lâattaquant
CrĂ©er/prĂ©senter des attestations apparemment valides (ou corrompre la vĂ©rification) pour faire accepter des authenticators contrĂŽlĂ©s par lâattaquant, permettant la connexion sans possĂ©der les comptes lĂ©gitimes (ou pour faciliter dâautres escroqueries/implantations).
đą DĂ©roulĂ© dĂ©taillĂ© de lâattaque (Ă©tapes)
- Compromission initiale
- Voie A : compromission dâun CA dâattestation (ex : vol de clĂ© privĂ©e dâun Ă©metteur dâattestation).
- Voie B : compromission dâun service intermĂ©diaire (magasin de certificats interne, FIDO Metadata Service mal protĂ©gĂ©, ou systĂšme dâingestion dâattestations).
- Voie C : social engineering + installation dâun certificat racine local (Windows) sur des postes ciblĂ©s (deux clics « Installer ce certificat »).
- Fabrication dâattestations malveillantes
- Lâattaquant utilise la clĂ© dâattestation volĂ©e (ou un CA compromis) pour signer des attestationObjects qui contiennent des clĂ©s publiques contrĂŽlĂ©es par lâattaquant.
- Ces attestations paraissent conformes au format attendu (
fmt = packed|tpm|fido-u2f|...
) et contiennent des chaßnes de certif valides ou faussées.
- EnrĂŽlement / propagation
- Lâattaquant enregistre massivement des credentials « lĂ©gitimes » sur des services ciblĂ©s (inscriptions automatisĂ©es via API ou via sessions de phishing ciblĂ©es).
- Si le serveur exige ou vĂ©rifie lâattestation, celle-ci passe la validation (CA compromise), donc le credential est acceptĂ©.
- Ăvasion & persistance
- Les credentials malveillants sont utilisés pour authentifier, contourner MFA, ou créer des sessions persistantes.
- Alternativement, lâattaquant installe des backdoors cĂŽtĂ© serveur (modifie vĂ©rifications, bypass origin checks) pour faciliter lâusage ultĂ©rieur.
- Escalade et exploitation
- Avec accĂšs, lâattaquant peut demander rĂ©initialisation dâaccĂšs, escroquerie interne, exfiltration, ou mouvement latĂ©ral vers des systĂšmes sensibles.
đ„ ConsĂ©quences pratiques
- Comptes compromis malgrĂ© lâusage de passkeys « hardware » ou « verified ».
- Perte de confiance dans la chaĂźne dâattestation ; nĂ©cessitĂ© dâun forcé rĂ©enregistrement massif.
- Impact fort si lâattaque touche un provider cloud (synchronisation passkey compromise).
- Coût opérationnel énorme (revocation, forensics, communication, obligations légales).
đ”ïž Signaux & indicateurs de compromission (logiques Ă surveiller)
- Pics dâenregistrement : vagues anormales dâenrĂŽlements dâauthenticators avec le mĂȘme AAGUID / mĂȘme chaĂźne dâattestation.
- Multiples credentialId associĂ©s Ă un mĂȘme attestation certificate serial.
- SignatureCounter qui nâaugmente pas correctement (ou qui augmente bizarrement) â clones ou authenticators non conformes.
- Origin / RP ID mismatches dans logs deÂ
clientDataJSON
 (tentatives dâinscription via des origins inattendues). - Ăchecs dâattestation parsing suivis dâacceptations manuelles ou bypass cĂŽtĂ© infra.
- ĂvĂ©nements SIEM : connexions rĂ©ussies hors horaires, IPs gĂ©o-anormales, nouveaux devices non inventoriĂ©s.
Exemples de requĂȘtes SIEM (pseudo) :
SELECT count(*) FROM webauthn_registrations WHERE aaguid = 'XXXX' AND timestamp > now()-1h GROUP BY serial
search logs where event='assertion' and signatureCounter <= previous_counter
đĄïž Mesures dâattĂ©nuation & bonnes pratiques (opĂ©rationnelles + techniques)
A. Gouvernance & politique dâattestation
- Politique claire : dĂ©finir si tu acceptesÂ
fmt=none
 ou si tu exiges attestation CA vĂ©rifiable. Pour les comptes sensibles, nâaccepte que les attestations vĂ©rifiĂ©es via FIDO MDS. - Inventory AAGUID : maintenir une liste blanche dâAAGUIDs approuvĂ©s (pour comptes sensibles).
- Rotation & rĂ©vo : prĂ©parer un plan de rĂ©vocation dâattestations (et dâIDs compromis) â pas trivial mais indispensable.
B. Renforcer la chaĂźne dâattestation
- ProtĂ©ger les PKI/CA : HSM pour les clĂ©s dâattestation, MFA forte pour accĂšs aux CA, audits rĂ©guliers, journaux immuables.
- Vérifier la Metadata FIDO : utiliser la FIDO Metadata Service pour valider les authenticators et détecter anomalies.
- Ne pas faire confiance aveuglément : cross-check du cert chain, vérifier les EK certs TPM/nonce si possible.
C. Durcissement cÎté client & OS
- Ăduquer utilisateurs : bloquer lâinstallation de certificats racine par utilisateurs non-admin ; renforcer politiques Windows GPO.
- Bloquer WebUSB / extensions non-trusted : restreindre extensions navigateur via listes blanches, désactiver WebUSB si non nécessaire.
D. Harden serveur & logging
- Valider strictement origin & RP IDÂ ; refuser tout mismatch.
- Vérifier challenge/session binding pour éviter replay.
- Stocker counters et monitorer ; alerter sur anomalies.
- Ne pas dĂ©lĂ©guer lâattestation aveuglĂ©ment : stocker la trace complĂšte de lâattestation pour forensics.
E. Processus de récupération & IR
- Processus de récupération robustes (réenregistrement avec 2 facteurs physiques, vérification manuelle).
- Playbook IR : isoler, révoquer credentials identifiés, forensics sur CA/metadata, communication aux tiers, forcing re-enroll.
- Table-top exercises sur scénarios de CA compromise.
đ Conclusion piquante
La passkey rend la vie plus dure aux phishing-kickers et aux failles classiques de mot de passe. Mais si tu confies la vĂ©rification Ă un magasin de certificats ou Ă une chaĂźne dâattestation non-protĂ©gĂ©e, tu donnes Ă un attaquant une clĂ© maĂźtresse morale : il pourra fabriquer lâapparence de lĂ©gitimitĂ©. En clair : la passkey te protĂšge dâun certain nombre dâattaques, pas dâune mauvaise gouvernance de la PKI. La sĂ©curitĂ© rĂ©elle vient dâun triptyque : implĂ©mentation correcte (19 points), chaĂźne dâattestation bien protĂ©gĂ©e, et procĂ©dures de rĂ©ponse testĂ©es
đđȘ WebAuthn & navigateurs â pourquoi le client web reste le maillon fragile
Les passkeys sont superbes⊠jusquâĂ ce que le navigateur fasse la connerie. WebAuthn repose sur un axiome : le navigateur fait bien son boulot (vĂ©rifie lâorigin, relaye proprement les challenges, nâexpose pas la clĂ© privĂ©e). Malheureusement, dans la vraie vie, le navigateur nâest pas un bunker inviolable â il a des extensions, des APIs riches (WebUSB, WebAuthn, WebCrypto, etc.), et un DOM qui peut ĂȘtre manipulĂ© par du code injectĂ©. Voici oĂč ça coince, et comment sâen prĂ©munir.
đ Extensions malveillantes et profils compromis
Les extensions de navigateurs sont une porte trop souvent laissĂ©e ouverte. Une extension malveillante ayant des permissions Ă©tendues (activeTab, webRequest, file access) peut injecter du JS dans des pages, modifier le DOM, ou intercepter des rĂ©ponses. RĂ©sultat : un script malveillant pourrait lancer des flows dâenregistrement/connexion (navigator.credentials.create()
/ navigator.credentials.get()
) en contexte utilisateur trompé, forcer des prompts, ou exfiltrer des métadonnées.
MĂȘme si la clĂ© privĂ©e ne sort jamais, une extension qui simule lâUX (popup biomĂ©trique factice) peut conduire Ă des actions dâacceptation par lâutilisateur. Bref : les extensions, câest la roulette russe.
Mitigation : force de la whitelist dâextensions via MDM/GPO, audit pĂ©riodique des extensions en production, et blocage des extensions non-essentielles pour les comptes Ă privilĂšges.
đ§Ż WebUSB, WebHID, WebBluetooth â trop de portes ouvertes
Les APIs modernes (WebUSB / WebHID / WebBluetooth) permettent aux pages dâinteragir avec du hardware. Combinaison dangereuse : une page piĂ©gĂ©e qui accĂšde Ă un authenticator mal configurĂ© (ou Ă un dongle USB mal protĂ©gĂ©) peut tenter des opĂ©rations non voulues. MĂȘme si WebAuthn reste soumis Ă origin checks et user gestures, ces APIs augmentent la surface dâattaque.
Mitigation : désactiver WebUSB/ WebHID dans les environnements sensibles via politiques navigateur, ou restreindre par extension.
âïž XSS + WebAuthn = mauvais mĂ©lange
Le modĂšle WebAuthn sâappuie fortement sur la confiance dans le DOM : si un site est vulnĂ©rable Ă une XSS, un attaquant peut injecter un script qui dĂ©clenche lâauthentification ou lâenregistrement, redirige les challenges, ou manipule lâUI pour tromper lâutilisateur. MĂȘme si clientDataJSON.origin
protĂšge contre le phishing cross-site, la XSS intervient sur le mĂȘme origin, donc lâorigin check devient inutile : tu es sur la mĂȘme origine, mais contrĂŽlĂ©e par lâattaquant.
En clair : WebAuthn arrĂȘte les phishers, pas un site lui-mĂȘme compromis.
Mitigation : renforcer CSP, audits XSS fréquents, SRI pour les scripts tiers, scanner automatisé des payloads XSS.
đ Attaques de relay / clickjacking & user gestures
WebAuthn exige souvent une interaction utilisateur. Les attaquants inventent des moyens de la simuler ou de la tromper (clickjacking, overlays, social engineering). Les techniques de relay (Evilginx-like) restent plus difficiles avec passkeys mais des variantes existent, notamment si la chaine dâattestation ou la logique serveur est faible.
Mitigation : SameSite cookies stricts, frame-ancestors CSP, protection anti-clickjacking, UI nette et non-spoofable cÎté OS (préférer prompts natifs).
đ§ La confiance dans le navigateur â et pourquoi câest un problĂšme dâinfra
WebAuthn ne remplace pas la nĂ©cessitĂ© dâun navigateur sĂ©curisĂ© : profils sync (sauvegarde de session), extensions, ou installations de certificats racine (via clics utilisateurs) peuvent compromettre la chaĂźne. Si un profil Chrome/Edge est sync et compromis, lâattaquant gagne un vecteur dâaccĂšs. Les entreprises doivent considĂ©rer le navigateur comme une piĂšce dâinfra critique Ă durcir.
Mitigation infra : dĂ©sactiver/sĂ©curiser le sync de profils pour comptes sensibles, contrĂŽler GPO/MDM, forcer mises Ă jour et appliquer policies dâextensions.
â Recommandations de base cĂŽtĂ© produit & infra
- Bloquer ou limiter les extensions pour comptes sensibles.
- Désactiver WebUSB/HID si inutiles.
- Mettre CSP strict et scanner XSS en continu.
- ForcerÂ
userVerification
 (uv
) pour opérations sensibles (exiger biométrie/PIN). - Afficher un prompt OS-natif non spoofable pour les actions critiques (hardware auth).
- Monitorer les enrollments anormaux et les patterns dâextensions.
đ InteropĂ©rabilitĂ© & migration dans les environnements legacy
đïž Le problĂšme de fond : lâentreprise nâest pas Google
Oui, les passkeys sont jolies quand tu as un écosystÚme flambant neuf et que tout ton SI tourne en SaaS moderne compatible WebAuthn. Dans la vraie vie, tu as :
- un Active Directory qui traĂźne depuis Windows Server 2008,
- un ERP (SAP, IBM i, AS/400) qui nâa jamais entendu parler de FIDO,
- des applis maison qui sâauthentifient encore en LDAP simple bind (oui, en clair parfois),
- et des VPN SSL oĂč on a bricolĂ© du SAML avec des bouts de scotch.
Bref : implĂ©menter les passkeys ne veut pas dire « appuyer sur ON ». Câest une migration progressive, avec des couches qui doivent cohabiter.
𧩠Les couches de compatibilité
1. Active Directory & Azure AD
- Azure AD (désormais Entra ID) sait gérer les passkeys nativement, intégrés à FIDO2.
- Mais ton AD on-prem ? LĂ , câest du Kerberos/NTLM, pas de WebAuthn. Pour faire le pont, tu dois mettre un Identity Provider moderne (ADFS, Ping, OktaâŠ) qui joue la traduction.
- ConsĂ©quence : le vrai login AD classique (Ctrl+Alt+Del) continuera longtemps dâexiger mot de passe ou smartcard. Les passkeys viendront surtout pour les apps web fĂ©dĂ©rĂ©es.
2. ERP & applis legacy
- SAP a introduit du support partiel (via SSO, SAML, OIDC).
- IBM i / AS400 ? LĂ , tu oublies WebAuthn natif. La seule option câest un proxy dâauthentification qui valide la passkey cĂŽtĂ© web et Ă©met un ticket interne (LDAP bind, EIM, etc.).
- Pour les applis maison, il faudra patcher : ajouter un module OIDC / SAML qui sache dialoguer avec un IdP passkey-compatible.
3. VPN & accÚs réseau
- Beaucoup de VPN (Cisco AnyConnect, Palo Alto, Fortinet) ajoutent petit Ă petit du support FIDO2. Mais encore beaucoup reposent sur RADIUS + LDAP.
- La migration passe par des proxies dâauthentification ou par lâajout dâune authentification adaptative : si passkey dispo â FIDO, sinon fallback mot de passe/MFA.
đžïž Lâarchitecture hybride en pratique
En réalité, tu auras une cohabitation :
- Des apps modernes â authentifiĂ©es 100% passkey via IdP.
- Des systĂšmes legacy â authentifiĂ©es par translation (SAML/OIDC â LDAP/Kerberos).
- Des comptes admin/domain controllers â encore en smartcards ou mots de passe costauds (parce que FIDO2 nâest pas partout).
Donc non, on ne devient pas « passwordless » du jour au lendemain. On vit dans un patchwork.
â ïž Les piĂšges typiques
- Double UX : lâutilisateur doit parfois se connecter avec passkey, parfois encore avec mot de passe â rĂ©sultat : confusion + tickets helpdesk.
- Fallbacks mal gĂ©rĂ©s : si tu gardes le mot de passe comme « secours » mais quâil est faible, tu as simplement dĂ©placĂ© le problĂšme.
- Licences & coĂ»ts IdP : beaucoup dâĂ©diteurs font payer le support passkeys/FIDO comme un module premium.
- SĂ©curitĂ© de la translation : un proxy dâauthentification mal configurĂ© devient la nouvelle « clĂ© de voĂ»te vulnĂ©rable ».
- Shadow IT : certains éditeurs SaaS non compatibles vont te forcer à garder les mots de passe, ce qui ruine la promesse « passwordless ».
đ ïž Bonnes pratiques pour la migration
- Cartographier les flux dâauthentification actuels (AD, LDAP, SAML, OIDC, VPN, applis internes).
- Prioriser : commencer par les apps web fédérées (portail RH, CRM, SharePoint Online).
- Installer un IdPÂ compatible FIDO2 qui sert de traducteur.
- Planifier le fallback : smartcards matérielles pour les comptes sensibles, mots de passe robustes pour les apps legacy mais sous politique renforcée.
- Former les utilisateurs : oui, il faudra encore leur dire « parfois passkey, parfois mot de passe », au moins au début.
- Surveiller : logs dâenrĂŽlement, anomalies, et flux hybrides.
đ§ Conclusion
Le marketing « passwordless » donne envie de croire que demain matin, tu te connectes partout avec ton empreinte digitale et basta. La rĂ©alitĂ©, câest que ton vieux SAP ou ton AS/400 nâa aucune idĂ©e de ce quâest une passkey â et quâun proxy mal fichu vaut un mot de passe rĂ©utilisĂ©.
La migration est donc plus une cohabitation bordĂ©lique quâune rĂ©volution instantanĂ©e. Les passkeys sont un outil puissant, mais elles ne font pas disparaĂźtre ton legacy dâun coup de baguette magique.
đ§° Bonnes pratiques dâimplĂ©mentation (sans paillettes)
Mettre en place des passkeys, ce nâest pas un bouton magique « passwordless ». Câest un vrai chantier technique et organisationnel. Voici la checklist Ă avoir sous la main avant de foncer tĂȘte baissĂ©e.
đ CĂŽtĂ© technique â devs & infra
- Valide tout : respecte la procĂ©dure WebAuthn complĂšte (19 points de validation). Origin, rpId, challenge, algorithme, counters â pas dâapproximation.
- Nâutilise pas du code maison : prends une librairie WebAuthn Ă©prouvĂ©e (ex. SimpleWebAuthn, WebAuthn4J, Duo-labs). Tu nâĂ©cris pas ton propre parseur CBOR Ă 3h du matin.
- Algorithmes stricts : impose ES256 (P-256) et refuse le reste si tu nâas pas de cas dâusage spĂ©cifique.
- Attestation policy : dĂ©cide si tu acceptesÂ
none
 ou si tu exiges une chaĂźne dâattestation vĂ©rifiĂ©e. Pour les comptes sensibles, whitelist dâAAGUID + vĂ©rif via FIDO Metadata Service. - Monitoring : logue tout (enrĂŽlements, assertions, mismatches, counters non incrĂ©mentĂ©s). Mets des alertes SIEM sur anomalies.
- Fallback solide : pas un simple reset par helpdesk avec une question secrÚte. Mets une procédure MFA manuelle, une preuve physique, ou une clé matérielle alternative.
đ§âđ» CĂŽtĂ© utilisateurs â lâUX
- Clarté : explique simplement à quoi sert une passkey (un badge numérique qui reste dans ton appareil).
- Multiples devices : documente le fonctionnement cloud sync (Apple iCloud, Google Password Manager, MS Authenticator). Si tu lâacceptes â assume la dĂ©pendance au vendor.
- Process de perte : dis clairement « si tu perds ton tĂ©lĂ©phone, voici comment tu rĂ©cupĂšres ». Rien de pire quâun utilisateur qui panique en croyant avoir perdu son job avec son smartphone.
- Communication : prĂ©pare des guides avec captures dâĂ©cran pour chaque OS/navigateur (sinon ton support va te haĂŻr).
đą CĂŽtĂ© organisation â lâentreprise
- Cartographie : liste toutes tes applis â lesquelles supportent WebAuthn, lesquelles sont legacy.
- Priorisation : commence par les applis SaaS fĂ©dĂ©rĂ©es (Office 365, Salesforce, CRM) â ROI rapide.
- Politiques dâaccĂšs : impose passkeys pour les comptes sensibles (admins AD, comptes cloud).
- MFA by design : la passkey est dĂ©jĂ une MFA (facteur device + biomĂ©trie/PIN). Mais ne lâoublie pas pour les environnements oĂč tu gardes des mots de passe.
- Shadow ITÂ : surveille les applis tierces non compatibles qui vont forcer les utilisateurs Ă garder des mots de passe.
â ïž Les « donât »
- â Ne fais pas confiance au navigateur « par dĂ©faut » : configure CSP, bloque les extensions, durcis le poste client.
- â Ne pense pas que les passkeys suppriment tous les risques â elles rĂ©duisent phishing & vol de mots de passe, pas la compromission du navigateur ni la corruption du serveur.
- â Ne garde pas un mot de passe faible comme « secours ». Câest comme verrouiller ta porte blindĂ©e et laisser la clĂ© sous le paillasson.
- â Nâignore pas la gouvernance PKI â un magasin de certificats compromis annule tout le gain de sĂ©curitĂ©.
â RĂ©sumĂ© (utile)
Tu veux ĂȘtre « passwordless » ? Parfait. Mais sois prĂȘt Ă :
- GĂ©rer une PKI et un IdP comme si ta vie en dĂ©pendait (parce que câest un peu le cas).
- Former tes utilisateurs pour Ă©viter quâils fassent nâimporte quoi.
- Accepter quâun monde hybride passkeys + legacy va durer longtemps.
- Répondre à un incident PKI en mode pompier (et avoir un plan écrit, pas sur un post-it).
đ·ïž Cas concret : attaque navigateur + WebAuthn (XSS et extension malveillante)
đ Le dĂ©cor
Imaginons une entreprise qui déploie fiÚrement les passkeys pour son portail RH. Tout est conforme : challenge signé, clé privée dans le TPM, origin check nickel.
Mais⊠le navigateur des utilisateurs est Chrome/Edge avec :
- des extensions non contrÎlées (ex. « gestionnaire de PDF » un peu louche),
- un portail RH codé vite-fait avec une faille XSS stockée (un champ « commentaire » non filtré).
đ§© Ătape 1 : lâinjection XSS
Un attaquant dĂ©pose un script malveillant dans le champ commentaire du portail RH. Lorsquâun utilisateur lĂ©gitime ouvre la page, le script sâexĂ©cute dans le mĂȘme origin que le portail (https://rh.entreprise.com
).
- Du coup, le script peut appeler directementÂ
navigator.credentials.get()
 pour lancer un flux WebAuthn. - Le navigateur ne voit aucun problÚme : origin valide, challenge renvoyé par le serveur, tout semble légitime.
đ§© Ătape 2 : manipulation DOM et UX
Le script affiche un faux pop-up (« Votre session a expiré, reconnectez-vous »).
Lâutilisateur clique, le navigateur demande la validation biomĂ©trique (empreinte, FaceID). Lâutilisateur valide sans se poser de questions.
RĂ©sultat : lâattaquant rĂ©cupĂšre une assertion signĂ©e valide, qui peut ĂȘtre relayĂ©e vers son propre serveur (attaque de type credential relay).
đ§© Ătape 3 : extension malveillante (option bonus)
Une extension installĂ©e par lâutilisateur (aprĂšs avoir cliquĂ© sur un joli bouton « installer ») peut aussi :
- Intercepter ou modifier les réponses du serveur.
- Injecter son propre JavaScript sur toutes les pages RH.
- Forcer lâappel Ă Â
navigator.credentials.create()
 pour enregistrer une nouvelle clĂ© publique sous contrĂŽle de lâattaquant (si la logique serveur est trop laxiste sur lâattestation).
đŻ RĂ©sultat
- Lâattaquant a un accĂšs utilisateur lĂ©gitime, validĂ© par WebAuthn.
- Le systĂšme a fait tout ce quâil fallait, mais la faille venait du navigateur (XSS, extensions) et du site vulnĂ©rable.
- La promesse « phishing-resistant » des passkeys est tenue⊠sauf que ça nâempĂȘche pas le compromis cĂŽtĂ© clientou le code malicieux dans ton propre site.
đ§ Mitigation (ou comment Ă©viter de se faire avoir)
- Durcissement appli web : CSP strict, nettoyage des entrées, XSS scanner, SRI sur scripts tiers.
- Durcissement navigateur : bloquer les extensions non approuvées (GPO/MDM), désactiver WebUSB/WebHID si inutile.
- UX anti-spoofing : prĂ©fĂ©rer prompts natifs (Windows Hello, TouchID) qui sâaffichent hors DOM, limitant les faux popups.
- Monitoring : surveiller les enregistrements inattendus (
navigator.credentials.create()
), origins, et flux de relai.
đĄ Morale piquante
Une passkey ne tâimmunise pas contre ton propre JavaScript pourri ni contre une extension que ton utilisateur a installĂ©e aprĂšs avoir cliquĂ© sur « Recevoir mes horoscopes quotidiens ».
En bref : tu ne peux pas te cacher derriÚre WebAuthn si ton site est une passoire XSS ou si tu laisses tes navigateurs en mode « Far West ».
đ€š Conclusion â « Tâes vraiment sĂ»r, on y va ? »
Alors, les passkeys, câest la fin des mots de passe ? Oui⊠et non.
- Oui, parce que tu réduis drastiquement le phishing et le credential stuffing (adieu les « azerty123 » recyclés sur 12 sites).
- Oui, parce que le support IT va moins se taper de tickets « jâai oubliĂ© mon mot de passe ».
- Oui, parce que câest plus fluide pour lâutilisateur final (un clic, une empreinte, basta).
Mais.
- Non, ça ne supprime pas le problÚme des applis legacy qui vivent encore en LDAP simple bind.
- Non, ça ne protÚge pas ton infra si ton magasin de certificats ou ta PKI est compromis.
- Non, ça nâempĂȘche pas un XSS bien placĂ© ou une extension malveillante de dĂ©tourner le flow cĂŽtĂ© navigateur.
- Non, ça ne tâexonĂšre pas de gouvernance : politique claire, procĂ©dures de rĂ©enrĂŽlement, plan IR testĂ©.
En fait, les passkeys ne sont pas le Saint-Graal du âpasswordlessâ, mais plutĂŽt une Ă©volution sĂ©rieuse du MFA. Elles rĂ©solvent un paquet de problĂšmes, mais elles en introduisent de nouveaux : dĂ©pendance aux gĂ©ants du cloud pour la synchro, complexitĂ© dâintĂ©gration dans ton SI legacy, gestion des fallback, et nĂ©cessitĂ© de durcir ton navigateur et ton code applicatif.
đŻ Le mot de la fin
Adopter les passkeys, câest comme passer dâun cadenas en plastique Ă une serrure Ă©lectronique biomĂ©trique : oui, câest plus costaud, mais si tu laisses la fenĂȘtre ouverte (XSS, PKI mal gĂ©rĂ©e, utilisateurs crĂ©dules), tu invites quand mĂȘme le cambrioleur Ă entrer.
Alors, tâes vraiment sĂ»r dâĂȘtre « passwordless » ? Ou tu viens juste dâacheter une nouvelle illusion de sĂ©curitĂ© qui fera joli dans le rapport annuel ?
ANNEXES
Playbook IR : Compromission du magasin dâattestation (PKI / CA / FIDO metadata)
Isoler rapidement lâimpact, identifier lâĂ©tendue (services / credentials affectĂ©s), empĂȘcher lâutilisation frauduleuse dâattestations malveillantes, restaurer la confiance et rĂ©-enrĂŽler de façon contrĂŽlĂ©e.
1) Activation & premiĂšres minutes (0â60 min)
Actions immédiates (qui, quoi) :
- Qui : SOC lead / on-call IR lead (R), Head of Security (A), Infra ops, App owners, Legal, Comms (I/C).
- Objectif : arrĂȘter lâhĂ©morragie, collecter preuves immuables, prĂ©server la chaĂźne de custody.
TĂąches urgentes :
- Isoler le(s) service(s) affectĂ©(s) : mettre en mode maintenance / disable enrollment endpoints API publiques (e.g.,Â
/webauthn/register
,Â/webauthn/assert
). - Activer journalisation complÚte (if not already): augmenter verbosité des logs WebAuthn, reverse proxies (NGINX/ALB), WAF, IdP/SSO logs.
- Collecter artefacts immuables : exporter snapshots des bases WebAuthn (credentialId, public key, attestationObject, aaguid, attestation cert chain, signatureCounter), export DB backups, capture memory on key servers if possible.
- Prendre images des serveurs/VMs et verrouiller accÚs administratif (change admin creds, block malicious sessions).
- Notifier legal / conformité si données à caractÚre personnel potentiellement impactées.
2) Investigation rapide (60â240 min)
Objectifs : confirmer compromission, scope, vecteur (CA private key leak, metadata poisoning, social install of root certs).
Checks techniques rapides :
- Inspecter attestations rĂ©cemment acceptĂ©es : rechercher patterns (mĂȘme issuer serial, mĂȘmes AAGUIDs, mĂȘme subject CN).
- VĂ©rifier FIDO MDS / metadata updates : timestamp/manifest rĂ©cents â anomalies de signature.
- Vérifier PKI / CA logs : accÚs aux HSM, opérations de signing inhabituelles.
- Vérifier endpoints de provisioning : IPs clients, user agents, origins liés aux nouveaux enregistrements.
RequĂȘtes SIEM / Splunk (exemples) :
- Splunk (pseudo) :Â
index=webauthn sourcetype=registration | stats count by aaguid, attestation_cert_serial | where count > 10
- ELK/Kibana (pseudo) :Â
POST /webauthn/_search { "query": { "bool": { "must": [{"match":{"event":"register"}}, {"range":{"@timestamp":{"gte":"now-1h"}}}]}}}
- Counter anomalies :Â
index=webauthn event=assertion | timechart span=1h count by signatureCounter
 â alerte si pattern non-incrĂ©mental.
Forensics (Windows/Linux):
- Windows: lister certificats racine utilisateur/local :Â
certutil -viewstore -user Root
 /Âcertutil -store My
 ; supprimer certificat racine malveillant :Âcertutil -delstore Root "<SerialNumber>"
. - PowerShell:Â
Get-ChildItem Cert:\LocalMachine\Root | Where-Object {$_.Thumbprint -eq "<thumbprint>"}
- Linux: vĂ©rifierÂ
/etc/ssl/certs
,Âopenssl x509 -in cert.pem -noout -text
 pour inspecter CN/SNs. - DB dump:Â
mysqldump --single-transaction --skip-lock-tables webauthn_db > dump.sql
 (preserve immutability, hash the dump). - Capture HTTP transactions (reverse-proxy logs): extract origins, user-agents, IPs.
3) Containment (4â24 h)
But : neutraliser lâusage des attestations compromises.
Actions techniques :
- Blacklister AAGUIDs / attestation cert serials dans ta DB dâenrĂŽlements et dans la validation : toute assertion provenant dâune credential avec ces AAGUID/serial â reject.
- DĂ©sactiver lâacceptation dâattestations signĂ©es par la CA compromise (update validate-attestation logic).
- Forcer rejection des nouveaux enregistrements: fermer endpointÂ
register
 public, autoriser uniquement via change control pour le réenrÎlement contrÎlé. - Bloquer synchronisation vendor-cloud (si enterprise utilise Apple/Google passkey sync) en informant les fournisseurs si nécessaire.
- Appliquer GPO / MDMÂ pour empĂȘcher lâinstallation de certificats racine par utilisateurs.
Opérations légÚres :
- Rotation des credentials dâadministration applicatifs qui ont pu ĂȘtre exposĂ©s.
- Patch immĂ©diat si tampering trouvĂ© sur serveur dâenrĂŽlement.
4) Eradication & remediation (24hâ7 jours)
- RĂ©voquer / marquer invalides les credentials identifiĂ©s : setÂ
status=revoked
 in DB, invalidate sessions. - Roll-back / reissue : si CA compromise â rĂ©voquer CA cert + publier CRL/OCSP, gĂ©nĂ©rer CA propre dans HSM, mise Ă jour de toute la chaine.
- Nettoyer endpoints, corriger vulnérabilités qui ont permis compromission (accÚs non MFA, ports ouverts, scripts non durcis).
- Auditer MDS : vérifier metadata authenticity; faire incident report to FIDO Alliance if metadata poisoned.
- Forensically analyse HSM logs; si fuite de key material confirmée, plan de remplacement total.
5) Recovery & re-enrollment (J+3 â J+30)
Objectif : restaurer accÚs légitime, minimiser friction.
Processus recommandé :
- Communiquer (voir templates ci-dessous) aux utilisateurs affectés : expliquer mesures, pas de panique, procédure de ré-enrÎlement.
- Ré-enrÎlement contrÎlé :
- Step 1 : administratively verify user identity (MFA + helpdesk validation).
- Step 2 : issue temporary fallback (time-limited OOB code) or require physical key (YubiKey) for high privilege.
- Step 3 : callÂ
navigator.credentials.create()
 only after verification. Log everything.
- Revoke old credentials en batch.
- Offer hardware keys for critical users (ops, admins): policy to require U2F/YubiKey for privileged accounts.
- Post-recovery monitoring: heightened monitoring 30 days, watch counters and enrollment patterns.
6) Communication â templates (rapide & efficace)
Internal (short) â to Execs:
Objet : Incident sĂ©curitĂ© â compromission magasin attestations (passkeys) â action et impact
RĂ©sumĂ© : Nous confirmons une compromission affectant la chaĂźne dâattestation utilisĂ©e pour les passkeys. Actions immĂ©diates : endpoints dâenrĂŽlement fermĂ©s, blacklist AAGUIDs, rĂ©vo des credentials suspects. Impact : possibilitĂ© de sessions frauduleuses limitĂ©e. Nous travaillons le containment, lâĂ©radication et la notification. DĂ©tails et next steps suivront.
User-facing (concise):
Objet : SĂ©curitĂ© â procĂ©dure de rĂ©-enrĂŽlement passkey
Contenu : Nous avons dĂ©tectĂ© une anomalie technique liĂ©e au systĂšme dâenrĂŽlement des passkeys. Par mesure de prĂ©caution, certains accĂšs vont ĂȘtre temporairement rĂ©initialisĂ©s. Vous recevrez un email avec instructions pour vous rĂ©-enregistrer. Nous nâavons pas de preuve de compromission directe de comptes individuels <ou prĂ©ciser si oui>. Merci de suivre les instructions.
Legal / regulators: prepare timeline + data scope; include forensic artifacts hash.
7) Monitoring & détection post-incident (alerts à déployer)
- Alarme :Â
New registrations from same attestation cert serial > N/hour
- Alarme :Â
signatureCounter decrease or no-increment
- Alarme :Â
Origin mismatch during registration
- Alarme :Â
Spike in DB writes to credentials table
- Alarme :Â
New attestation format fmt not in whitelist
8) RÎles & responsabilités (RACI bref)
- RÂ : SOC (detection), IR lead (orchestration), App owner (closure)
- AÂ : Head of Security
- CÂ : Legal, Comms, Vendor support (Yubico / FIDO)
- IÂ : Execs, affected user groups
9) Post-mortem & actions long terme (30â90 jours)
- Rotate PKI, force metadata re-validation, mandate hardware keys pour admins, update runbooks, run TTX (table-top exercises) sur CA compromise, renforcer governance FIDO MDS, GPO pour cert installation.
Annexes techniques utiles
Commands / snippets (concise)
- Export webauthn table (MySQL):
mysqldump -u root -p webauthn_db credentials > webauthn_credentials.sql && sha256sum webauthn_credentials.sql
- Inspect cert (OpenSSL):
openssl x509 -in attestation_cert.pem -noout -text
- Delete Windows cert by thumbprint:
certutil -delstore Root "THUMBPRINT"
- Example Splunk:
index=webauthn sourcetype=webauthn_register | stats count by att_cert_serial, aaguid | where count>5
Conclusion â la morale amĂšre
Tant que tu dĂ©pends dâune chaĂźne dâattestation, tu dois gĂ©rer la PKI comme un bijou : HSM, rotation, monitoring, et playbooks testĂ©s. Les passkeys ferment de grandes portes aux attaques classiques, mais si tu laisses la cave (PKI/metadata) ouverte, un attaquant rentre par la cheminĂ©e.
đ Cadeau : script PowerShell pour dĂ©tecter et lister certificats racine rĂ©cemment installĂ©s sur un parc.
<# PowerShell script â Detecter et lister les certificats racine rĂ©cemment installĂ©s sur un parc Fonctions: - Get-RootCertificates : liste les certificats des stores Root (LocalMachine + CurrentUser) pour un hĂŽte - Save-CertsBaseline : enregistre un baseline CSV pour comparaison ultĂ©rieure - Compare-CertsBaseline : compare l'Ă©tat courant Ă un baseline et retourne les certificates ajoutĂ©s/supprimĂ©s - Find-RecentCerts : heuristique qui retourne les certificats dont NotBefore est dans les X derniers jours - Collect-FromHosts : collecte les certificats depuis plusieurs machines via Invoke-Command (WinRM) Limitations importantes: - Windows ne stocke pas un "install timestamp" explicite pour un certificat dans le store. Nous utilisons deux approches: 1) comparaison par baseline (fiable si vous avez une baseline antĂ©rieure) 2) heuristique sur le champ NotBefore (indique la date de validitĂ©, pas la date d'installation â utile comme indice) - Pour inventaire Ă l'Ă©chelle, activez WinRM / PSRemoting et exĂ©cutez Collect-FromHosts avec des comptes ayant droits d'administration. Usage exemple (local): # crĂ©er un baseline Save-CertsBaseline -FilePath "C:\temp\certs_baseline.csv" -IncludeCurrentUser:$false # vĂ©rifier les changements depuis le baseline Compare-CertsBaseline -FilePath "C:\temp\certs_baseline.csv" -IncludeCurrentUser:$false # trouver les certs avec NotBefore dans les 30 derniers jours Find-RecentCerts -Days 30 -IncludeCurrentUser:$false Usage exemple (parc): $hosts = @('host1','host2') $cred = Get-Credential Collect-FromHosts -ComputerNames $hosts -Credential $cred -OutputDir "C:\temp\webauthn_inventory" #> function Get-RootCertificates { [CmdletBinding()] param( [Parameter()] [bool]$IncludeCurrentUser = $true ) $results = @() # LocalMachine Root try { $lm = Get-ChildItem -Path Cert:\LocalMachine\Root -ErrorAction Stop foreach ($c in $lm) { $results += [PSCustomObject]@{ Store = 'LocalMachine\\Root' Thumbprint = $c.Thumbprint Subject = $c.Subject Issuer = $c.Issuer NotBefore = $c.NotBefore NotAfter = $c.NotAfter HasPrivateKey= $c.HasPrivateKey FriendlyName = $c.FriendlyName SerialNumber = $c.SerialNumber SignatureAlgorithm = $c.SignatureAlgorithm.FriendlyName RawDataHash = ([System.BitConverter]::ToString(($c.GetCertHash()))).Replace('-','') ExportedAt = (Get-Date) } } } catch { Write-Warning "Impossible d'Ă©numĂ©rer Cert:\LocalMachine\Root - $_" } if ($IncludeCurrentUser) { try { $cu = Get-ChildItem -Path Cert:\CurrentUser\Root -ErrorAction Stop foreach ($c in $cu) { $results += [PSCustomObject]@{ Store = 'CurrentUser\\Root' Thumbprint = $c.Thumbprint Subject = $c.Subject Issuer = $c.Issuer NotBefore = $c.NotBefore NotAfter = $c.NotAfter HasPrivateKey= $c.HasPrivateKey FriendlyName = $c.FriendlyName SerialNumber = $c.SerialNumber SignatureAlgorithm = $c.SignatureAlgorithm.FriendlyName RawDataHash = ([System.BitConverter]::ToString(($c.GetCertHash()))).Replace('-','') ExportedAt = (Get-Date) } } } catch { Write-Warning "Impossible d'Ă©numĂ©rer Cert:\CurrentUser\Root - $_" } } return $results } function Save-CertsBaseline { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$FilePath, [bool]$IncludeCurrentUser = $true ) $data = Get-RootCertificates -IncludeCurrentUser:$IncludeCurrentUser $data | Select-Object Store, Thumbprint, Subject, Issuer, NotBefore, NotAfter, HasPrivateKey, FriendlyName, SerialNumber, SignatureAlgorithm, RawDataHash, ExportedAt | Export-Csv -Path $FilePath -NoTypeInformation -Encoding UTF8 Write-Host "Baseline saved to $FilePath" -ForegroundColor Green } function Compare-CertsBaseline { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$FilePath, [bool]$IncludeCurrentUser = $true ) if (-not (Test-Path $FilePath)) { throw "Baseline file not found: $FilePath" } $baseline = Import-Csv -Path $FilePath $current = Get-RootCertificates -IncludeCurrentUser:$IncludeCurrentUser # Nouveaux certificats = prĂ©sents dans current mais pas dans baseline (par Thumbprint) $new = $current | Where-Object { -not ($baseline.Thumbprint -contains $_.Thumbprint) } # Certificats supprimĂ©s = prĂ©sents dans baseline mais pas dans current $removed = $baseline | Where-Object { -not ($current.Thumbprint -contains $_.Thumbprint) } $report = [PSCustomObject]@{ GeneratedAt = (Get-Date) NewCerts = $new RemovedCerts= $removed BaselineFile = (Get-Item $FilePath).FullName } # Affichage confort if ($new.Count -gt 0) { Write-Host "Nouveaux certificats dĂ©tectĂ©s : $($new.Count)" -ForegroundColor Yellow $new | Format-Table Thumbprint, Subject, Issuer, NotBefore, Store -AutoSize } else { Write-Host "Aucun nouveau certificat dĂ©tectĂ©." -ForegroundColor Green } if ($removed.Count -gt 0) { Write-Host "Certificats retirĂ©s depuis le baseline : $($removed.Count)" -ForegroundColor Magenta $removed | Format-Table Thumbprint, Subject, Issuer, NotBefore, Store -AutoSize } return $report } function Find-RecentCerts { [CmdletBinding()] param( [int]$Days = 30, [bool]$IncludeCurrentUser = $true ) $cutoff = (Get-Date).AddDays(-1 * [int]$Days) $current = Get-RootCertificates -IncludeCurrentUser:$IncludeCurrentUser # Heuristique : NotBefore rĂ©cent $recentByNotBefore = $current | Where-Object { $_.NotBefore -ge $cutoff } # Heuristique alternative : certs dont ExportedAt rĂ©cent (utile si baseline non dispos) $recentByExport = $current | Where-Object { $_.ExportedAt -ge $cutoff } return [PSCustomObject]@{ Cutoff = $cutoff RecentByNotBefore = $recentByNotBefore RecentByExport = $recentByExport } } function Collect-FromHosts { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string[]]$ComputerNames, [Parameter(Mandatory=$true)] [System.Management.Automation.PSCredential]$Credential, [Parameter(Mandatory=$true)] [string]$OutputDir, [bool]$IncludeCurrentUser = $false ) if (-not (Test-Path $OutputDir)) { New-Item -Path $OutputDir -ItemType Directory | Out-Null } $scriptBlock = { param($IncludeCurrentUser) # retourner la table de certificats simplifiĂ©e $res = @() try { $lm = Get-ChildItem -Path Cert:\LocalMachine\Root -ErrorAction Stop } catch {$lm = @()} foreach ($c in $lm) { $res += [PSCustomObject]@{ Host = $env:COMPUTERNAME Store = 'LocalMachine\\Root' Thumbprint = $c.Thumbprint Subject = $c.Subject Issuer = $c.Issuer NotBefore = $c.NotBefore NotAfter = $c.NotAfter FriendlyName = $c.FriendlyName SerialNumber = $c.SerialNumber } } if ($IncludeCurrentUser) { try { $cu = Get-ChildItem -Path Cert:\CurrentUser\Root -ErrorAction Stop } catch {$cu = @()} foreach ($c in $cu) { $res += [PSCustomObject]@{ Host = $env:COMPUTERNAME Store = 'CurrentUser\\Root' Thumbprint = $c.Thumbprint Subject = $c.Subject Issuer = $c.Issuer NotBefore = $c.NotBefore NotAfter = $c.NotAfter FriendlyName = $c.FriendlyName SerialNumber = $c.SerialNumber } } } return $res } foreach ($host in $ComputerNames) { Write-Host "Collecte depuis $host ..." -ForegroundColor Cyan try { $out = Invoke-Command -ComputerName $host -Credential $Credential -ScriptBlock $scriptBlock -ArgumentList $IncludeCurrentUser -ErrorAction Stop $file = Join-Path $OutputDir "certs_$host.csv" $out | Export-Csv -Path $file -NoTypeInformation -Encoding UTF8 Write-Host "ExportĂ©: $file" -ForegroundColor Green } catch { Write-Warning "Ăchec collection depuis $host : $_" } } } # Helper: suppression (manuelle & prudente) d'un certificat racine sur la machine locale function Remove-RootCertificate { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$Thumbprint, [ValidateSet('LocalMachine','CurrentUser')] [string]$StoreLocation = 'LocalMachine' ) $storePath = "Cert:\$StoreLocation\Root" try { $c = Get-ChildItem -Path $storePath | Where-Object { $_.Thumbprint -eq $Thumbprint } if ($null -eq $c) { Write-Warning "Certificat $Thumbprint introuvable dans $storePath"; return } Write-Host "Suppression du certificat $Thumbprint dans $storePath" -ForegroundColor Yellow # action destructive: ask confirmation Remove-Item -Path ($c.PSPath) -Confirm } catch { Write-Error "Erreur lors de la suppression: $_" } } <# Exemples d'utilisation rapide: # 1) Sauvegarder un baseline local Save-CertsBaseline -FilePath "C:\temp\certs_baseline.csv" -IncludeCurrentUser:$false # 2) Comparer le baseline Compare-CertsBaseline -FilePath "C:\temp\certs_baseline.csv" -IncludeCurrentUser:$false # 3) Chercher les certs dont NotBefore < 30 jours Find-RecentCerts -Days 30 -IncludeCurrentUser:$false | Select-Object -ExpandProperty RecentByNotBefore | Format-Table -AutoSize # 4) Collecter depuis 2 hĂŽtes (WinRM requis) $hosts = @('host1','host2') $cred = Get-Credential Collect-FromHosts -ComputerNames $hosts -Credential $cred -OutputDir "C:\temp\webauthn_inventory" -IncludeCurrentUser:$false # 5) Supprimer manuellement un certificat (locale) Remove-RootCertificate -Thumbprint "âDEADBEEF..." -StoreLocation LocalMachine #>