Leçons de production sur alg none
Pourquoi l’ancien bug alg none compte encore, comment il revient dans les services modernes et comment le tester proprement.
L’histoire de alg: none passe souvent pour un vieux conte autour des JWT, pourtant je la vérifie encore pendant des audits réels. Ce n’est pas parce que toutes les bibliothèques acceptent aujourd’hui les jetons non signés. C’est parce qu’un système en production ne valide presque jamais les jetons dans un seul endroit propre. Une passerelle vérifie la signature, un worker interne décode seulement les claims, et une route d’administration fait confiance à un en-tête supposé privé. Voilà comment une vieille classe de bug trouve de nouveaux endroits où survivre.
Ce qui casse vraiment
L’échec n’est généralement pas une bibliothèque qui annonce que les jetons non signés sont acceptables. La forme dangereuse vient plutôt d’un chemin développeur où la vérification était optionnelle en local et où l’option est restée. Dans les piles Node, Python, Java ou Go, le motif se ressemble: le code décode le jeton pour lire sub, role ou tenant_id, puis suppose qu’une autre couche l’a déjà vérifié. L’attaquant n’a pas besoin d’être élégant. Il retire la signature, place {"alg":"none"} dans l’en-tête et modifie un claim qui change l’autorisation.
Un bon test compare les réponses, pas seulement les codes HTTP. Si /api/me rejette le jeton mais que /api/admin/reports renvoie une erreur différente après modification du claim, il y a une information. Peut-être que le jeton a été parsé avant vérification. Peut-être que les journaux d’autorisation contiennent maintenant des identifiants contrôlés par l’attaquant. Ce n’est pas anodin.
Séquence de test utile
Pars d’un jeton valide appartenant à un compte peu privilégié. Décode-le localement, conserve la structure du payload et crée une variante non signée. Change un seul claim à la fois. role est bruyant, mais tenant_id, scope, aud et les flags de fonctionnalités révèlent souvent davantage. Envoie le jeton vers des endpoints servis par des middlewares différents: APIs de jobs, résolveurs GraphQL, téléchargements de fichiers et routes JSON d’administration ajoutées tardivement.
Ce que les défenseurs doivent journaliser
Les échecs de vérification doivent être précoces et ennuyeux. Journalise l’algorithme d’en-tête, le kid, l’émetteur, l’audience, le chemin et la raison du rejet, jamais le jeton brut. Alerte spécifiquement sur alg: none, car cela indique une manipulation active plutôt qu’une expiration normale. Ajoute aussi un test négatif en CI pour faire passer un jeton non signé dans chaque vérificateur.
La leçon à retenir
La correction relève de la politique d’implémentation, pas seulement d’une mise à jour de dépendance. Les vérificateurs doivent fixer les algorithmes autorisés dans le code, rejeter les jetons avant lecture des claims et exposer une seule interface interne pour les claims fiables. Si un handler peut appeler un helper de décodage générique et récupérer un dictionnaire, quelqu’un finira par l’utiliser pour autoriser. Rends le chemin sûr plus court que le chemin dangereux.