← All posts

Un fournisseur d'identité nous a dit qui vous étiez, et nous l'avons cru

Authagonal·July 6, 2026
authsecurityssosamloidcfederation

L'authentification unique repose sur une prémisse discrète : lorsqu'un utilisateur arrive depuis un fournisseur d'identité, ce fournisseur s'est déjà porté garant de lui, on peut donc sauter le mot de passe et simplement le laisser entrer. Tout l'intérêt est de faire confiance à l'IdP. Le bogue que nous allons décrire vivait dans l'écart entre « faire confiance à l'IdP pour authentifier ses propres utilisateurs » et « faire confiance à tout ce que l'IdP vous raconte sur l'identité de ses utilisateurs ». Ce ne sont pas la même phrase, et la différence fut une prise de contrôle de compte.

Voici le contexte. Un locataire de notre plateforme peut configurer des connexions fédérées : SAML vers son IdP d'entreprise, OIDC vers un autre. Un utilisateur se connecte via l'une de ces connexions, l'IdP renvoie une assertion, et notre serveur doit répondre à une question : de quel compte local s'agit-il ? Faites erreur sur ce rapprochement et vous obtenez soit un inconnu enfermé dehors de son propre compte, soit, bien pire, un inconnu qui pénètre dans le compte de quelqu'un d'autre.

La clé de jointure était un e-mail, et un e-mail n'est qu'une revendication

Notre code répondait à « de quel compte s'agit-il » de la manière évidente. L'assertion portait un e-mail, alors nous recherchions l'utilisateur par celui-ci : FindByEmailAsync(assertedEmail). Si un compte correspondant existait, l'utilisateur fédéré récurrent y était résolu et connecté. Propre, simple, et exactement la manière dont beaucoup d'intégrations SSO sont écrites.

Le problème, c'est ce qu'est réellement cet e-mail. Ce n'est pas un fait que l'IdP a prouvé. C'est une chaîne de caractères dans une assertion, et l'assertion n'est digne de confiance que dans la mesure où l'est la connexion par laquelle elle est arrivée. Dans un monde multi-locataire, on ne contrôle pas toutes les connexions. Quiconque peut en monter une (son propre IdP SAML, son propre fournisseur OIDC) peut mettre la chaîne de son choix dans le champ e-mail. Ainsi une connexion à laquelle vous ne faites pas confiance affirme email = [email protected], notre recherche trouve le vrai compte du PDG, et l'attaquant est connecté en tant que lui. Aucun mot de passe, aucun hameçonnage, aucune faille dans la cryptographie. La signature de l'assertion était parfaitement valide. Elle se portait simplement garante d'une revendication que nous n'aurions jamais dû traiter comme une identité.

Le plus troublant, c'est que chaque pièce prise individuellement fonctionnait. L'IdP a authentifié son propre utilisateur correctement. La signature a été vérifiée. Le compte existait. La prise de contrôle n'était l'échec d'aucune vérification ; c'était l'usage du mauvais champ comme clé.

Pourquoi davantage de validation n'est pas le correctif

La réaction tentante est de valider l'e-mail plus durement. Exiger email_verified. Vérifier le domaine. Ajouter une règle. Mais observez la forme du piège : l'attaquant contrôle l'assertion, donc toute propriété que vous lisez dans l'assertion est une propriété que l'attaquant peut définir. Exiger email_verified = true d'une connexion que l'attaquant possède, c'est confier la bergerie au loup. On ne peut pas valider sa sortie de la confiance accordée à la mauvaise source.

L'e-mail convient comme commodité. C'est une clé primaire épouvantable, car il est global (la même adresse peut apparaître chez de nombreux fournisseurs) et falsifiable (il est ce que dit la connexion qui l'affirme). Une clé de jointure ne doit être ni l'un ni l'autre.

Le correctif était de changer la clé, pas d'ajouter des vérifications

Le vrai correctif était de cesser totalement de joindre sur l'e-mail et de joindre sur la seule chose qu'une connexion ne peut falsifier pour un fournisseur qu'elle ne possède pas : la paire (provider, sub). Le sub est l'identifiant de sujet que le fournisseur émet pour cet utilisateur, restreint à ce fournisseur. Un utilisateur récurrent est résolu en recherchant l'identité locale précédemment liée au (provider, sub) de cette connexion. La connexion d'un attaquant a son propre identifiant de fournisseur ; elle peut forger n'importe quel sub au sein de son propre espace de noms, mais elle ne peut pas produire le (provider, sub) de la connexion de quelqu'un d'autre. L'espace de noms est la douve.

L'e-mail retombe alors au rôle qu'il aurait toujours dû avoir : un indice pour lier, jamais pour résoudre, et seulement lorsqu'il fait l'objet d'une garantie. Nous faisons correspondre un e-mail affirmé à un compte existant uniquement lorsque l'e-mail est vérifié par une source à laquelle nous faisons réellement confiance pour ce domaine : email_verified provenant d'une connexion dont le domaine figure dans les AllowedDomains du locataire. En dehors de cela, une nouvelle identité fédérée obtient son propre compte, pas celui d'un autre.

La leçon, mise en facteur

Lorsque vous fédérez l'identité, séparez deux questions que vous êtes tenté de fusionner. « Ce fournisseur a-t-il authentifié cet utilisateur ? » trouve sa réponse dans la signature. « Qui est cet utilisateur dans mon système ? » doit trouver sa réponse dans une clé que la partie qui affirme ne peut falsifier au-delà des frontières, ce qui signifie un sujet propre au fournisseur, et non un attribut global comme l'e-mail. Traitez chaque champ d'une assertion comme contrôlé par l'attaquant, à moins que la source précise de ce champ ne soit une source à laquelle vous faites confiance pour cette revendication précise. L'e-mail est le champ vers lequel les gens se tournent en premier parce qu'il est humain et qu'il a l'air unique. C'est exactement le mauvais.

Nous avons livré ceci dans le cadre d'une passe de sécurité avant le lancement sur notre propre serveur d'authentification, avant que quiconque ne nous confie ses identifiants. C'est le genre de bogue qui passe tous les tests, vérifie toutes les signatures, et remet les clés à quiconque les demande dans le bon format. Le correctif n'était pas une meilleure serrure. C'était de réaliser que nous avions lu la mauvaise ligne de la pièce d'identité.

Fédérer l'identité en toute sécurité revient à joindre sur une clé que la partie qui affirme ne peut falsifier, et s'y prendre mal, c'est une prise de contrôle de compte qui passe tous les tests. Authagonal résout les utilisateurs fédérés par leur sujet propre au fournisseur, jamais par l'e-mail contenu dans l'assertion.