Pour renforcer la sécurité de votre système d'authentification, je vous propose de découvrir comment fonctionne l'authentification à deux facteurs TOTP (Time-based One-Time Password) et de l'implémenter en PHP.
Nous utiliserons pour cela la librairie TwoFactorAuth ainsi que l'application Google Authenticator pour générer automatiquement nos codes d'authentification.
Code source :
- config.php
<?php session_start(); require('./vendor/autoload.php'); try { $db = new PDO("mysql:host=localhost;dbname=double_auth", 'root', 'root'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e) { echo "Connection failed: " . $e->getMessage(); }
- index.php
<form action="register.php" method="POST"> <input name="email" type="email" placeholder="Email" /><br /> <input name="password" type="password" placeholder="Mot de passe" /><br /> <button type="submit">Inscription</button> </form>
- register.php
<?php require('./config.php'); if (!empty($_POST['email']) && !empty($_POST['password'])) { $email = $_POST['email']; $password = password_hash($_POST['password'], PASSWORD_DEFAULT); var_dump($email); var_dump($password); $q = $db->prepare('INSERT INTO users (email, password) VALUES (:email, :password)'); $q->bindValue('email', $email); $q->bindValue('password', $password); $res = $q->execute(); if ($res) { echo "Inscription réussie"; } }
- login.php
<?php require('./config.php'); use RobThreeAuthTwoFactorAuth; if (!empty($_POST['email']) && !empty($_POST['password'])) { var_dump($_POST); $email = $_POST['email']; $password = $_POST['password']; $tfaCode = $_POST['tfa_code']; $q = $db->prepare('SELECT * FROM users WHERE email = :email'); $q->bindValue('email', $email); $q->execute(); $user = $q->fetch(PDO::FETCH_ASSOC); var_dump($user); if ($user) { $passwordHash = $user['password']; if (password_verify($password, $passwordHash)) { $tfa = new TwoFactorAuth(); if (!$user['secret'] || $tfa->verifyCode($user['secret'], $tfaCode)) { $_SESSION['user_id'] = $user['id']; header('location:/profile.php'); exit(); } else { echo "Code 2FA invalide"; } } else { echo "Identifiants invalides"; } } else { echo "Identifiants invalides"; } }
- profile.php
<?php require('./config.php'); use RobThreeAuthTwoFactorAuth; $tfa = new TwoFactorAuth(); if (empty($_SESSION['tfa_secret'])) { $_SESSION['tfa_secret'] = $tfa->createSecret(); } $secret = $_SESSION['tfa_secret']; if (empty($_SESSION['user_id'])) { header('location:/'); exit(); } if (!empty($_POST['tfa_code'])) { if ($tfa->verifyCode($secret, $_POST['tfa_code'])) { $q = $db->prepare('UPDATE users SET secret = :secret WHERE id = :id'); $q->bindValue('secret', $secret); $q->bindValue('id', $_SESSION['user_id']); $q->execute(); } else { echo "Code invalide"; } } $userReq = $db->prepare('SELECT * FROM users WHERE id = :id'); $userReq->bindValue('id', $_SESSION['user_id']); $userReq->execute(); $user = $userReq->fetch(PDO::FETCH_ASSOC); ?> <h1>Votre profil</h1> <a href="/logout.php">Déconnexion</a> <?php var_dump($user) ?> <h2>Activation Double Authentification</h2> <?php if (!$user['secret']): ?> <p>Code secret : <?= $secret ?></p> <p>QR Code :</p> <img src="<?= $tfa->getQRCodeImageAsDataUri('Tuto', $secret) ?>"> <form method="POST"> <input type="text" placeholder="Vérification Code" name="tfa_code"> <button type="submit">Valider</button> </form> <?php else: ?> <p>2FA activée</p> <?php endif ?>
- logout.php
<?php require('./config.php'); $_SESSION = []; session_destroy(); header('location:/'); exit();
Ressources utiles :
- Spécification techinque des TOTP (RFC 6238)
- Librairie PHP TwoFactorAuth
- Documentation TwoFactorAuth (voir "Getting started" et "QR Codes" notamment)
- Installer Composer
- Installer Googler Authenticator : Android ou iOS
Sources :
- TOTP: (way) more secure than SMS, but more annoying than Push, Conor Gilsenan
- One Time Password (OTP, TOTP) : definition, examples, Thales Group
- What protects 2FA secret in a data leak? (discussion)
- Time-based One-time Passwords (TOTP), Gangani Chamika
- HOTP vs TOTP: Differences and advantages, Ana Vilar García
- RobThree/TwoFactorAuth demo.php
Votre commentaire