Le mot de passe est mort ! Vive le mot de passe !
Mais seul, le mot de passe ne vaut rien. Il suffit d'une fuite de base de données chez un tiers, et votre admin est compromis.
Il vous faut un deuxième verrou. Une Double Authentification (2FA).
Mais attention : n'implémentez pas ça n'importe comment. Pas de secrets stockés en clair. Pas de QR codes générés à la volée sur le front sans protection.
La stratégie de la confiance zéro
J'utilise le standard de l'industrie SchebTwoFactorBundle, mais avec une implémentation stricte :
- Le serveur stocke le secret TOTP.
- L'entité
Userest seule garante de sa configuration via une classe anonyme. - L'authentification est déléguée au Bundle qui intercepte le login.
Tout se passe côté backend : la commande affiche le code de synchronisation et enregistre temporairement le QR code.
Notre arsenal pour metre en place la double authentification
On ne réinvente pas la crypto.
- scheb/2fa-bundle : L'intégration Symfony standard et robuste.
- Endroid QrCode : Pour générer l'image.
- PHP 8.4 : Pour les Property Hooks et les classes anonymes
readonly.
La POO au service du Secret
L'entité User ne doit pas juste avoir un secret. Elle doit être authentifiable.
J'utilise une classe anonyme en lecture seule pour encapsuler la configuration TOTP à la volée C'est élégant et c'est PHP 8.4 friendly !
// User.php
public function getTotpAuthenticationConfiguration(): ?TotpConfigurationInterface
{
// Si l'authentification TOTP n'est pas activée ou pas configurée, retourner null
if (!$this->totpEnabled || null === $this->totpSecret) {
return null;
}
// Encapsulation totale via classe anonyme readonly
return new readonly class($this->totpSecret) implements TotpConfigurationInterface {
public function __construct(private string $secret) {}
public function getSecret(): string { return $this->secret; }
public function getAlgorithm(): string { return 'sha1'; } // Standard Google Auth
public function getPeriod(): int { return 30; }
public function getDigits(): int { return 6; }
};
}
4. La Configuration du Bundle
Plutôt que de tout coder à la main, le bundle dispose d'une configuration pour sécuriser les jetons.
return static function (ContainerConfigurator $containerConfigurator): void {
$schebTwoFactor = [
'security_tokens' => [
UsernamePasswordToken::class,
// On sécurise aussi les tokens post-auth si besoin
PostAuthenticationToken::class,
],
'totp' => [
'enabled' => true,
'server_name' => 'Lecodeestdanslepre', // Apparaît dans l'app de double authentification
'issuer' => 'Lecodeestdanslepre', // Apparaît dans l'app de double authentification
'template' => 'security/2fa_form.html.twig', // Le template personnalisé
],
];
// ...
};
Cette configuration garantit que tout utilisateur connecté via mot de passe DOIT valider son 2FA si totpEnabled est vrai.
Pourquoi ne pas le faire soi-même ?
J'ai vu des développeurs stocker le code 2FA en session, ou le générer en JavaScript. C'est une erreur.
Le bundle scheb/2fa-bundle gère :
- La protection contre le Brute Force sur le code 2FA.
- La fenêtre de validité (Clock Drift).
- La session de confiance (ne pas redemander le code à chaque URL).
En sécurité, mieux vaut déléguer à une bibliothèque éprouvée plutôt que de risquer une faille d'implémentation.
Le mot de la fin
La sécurité n'est pas une fonctionnalité !
C'est une architecture.
En combinant la puissance d'un Bundle communautaire avec la rigueur de PHP 8.4 (Types, Readonly Class), vous transformez votre application en forteresse, sans réinventer la roue carrée.
Les hackers passeront leur chemin pour aller attaquer le site de votre concurent.