Archives par mot-clé : sécurité

Double authentification et Symfony 5.1

Dans un article précédent, j’utilisais Guard pour réaliser un mécanisme de double authentification (si vous ne voyez pas de quoi je parle, lisez ce blog post « Double authentification avec Symfony »). J’ai souhaité le mettre à jour pour utiliser la nouvelle fonctionnalité introduite dans Symfony 5.1.

Avertissement

La fonctionnalité dont je vais parler est expérimentale ! Elle est susceptible d’être modifiée sans garantie de rétrocompatibilité dans les prochaines versions de Symfony 5.2 et suivante.

Cette fonctionnalité redessine la façon de fonctionner des classes d’authentification en se basant sur les évents. Ainsi les nouvelles classes d’authentification qui ressemblent un peu à celle de Guard génèrent un passeport contenant toutes les informations nécessaires pour la validation de l’authentification.

Pour ce blog post, j’ai préféré vous présenter cette migration sous forme de questions et réponses.

Comment fonctionne la classe d’authentification ?

Premier point, une classe d’authentification doit (comme pour Guard) dire si oui ou non il supporte la requête en cours. Si oui, la méthode authenticate est appelée et devra retourner un objet qui implémente l’interface PassportInterface.

La méthode authenticate doit :

  • Charger l’utilisateur depuis le fournisseur d’utilisateur.
  • Collecter les informations d’authentification (depuis la requête en général).
  • Générer le passeport avec la liste des badges nécessaires.

Comment sont vérifiées les informations d’authentification ?

Lors de la construction du passeport, le premier argument est l’objet utilisateur qui implémente l’interface UserInterface de Symfony. Le second est un « badge » spécifique qui implémente l’interface CredentialsInterface. Cet objet contiendra les informations d’authentification saisie par l’utilisateur qui tente de se connecter.

<?php
namespace Symfony\Component\Security\Http\Authenticator\Passport;
//...
class Passport implements UserPassportInterface
{
//...
    /**
     * @param CredentialsInterface $credentials the credentials to check for this authentication, use
     *                                          SelfValidatingPassport if no credentials should be checked.
     * @param BadgeInterface[]     $badges
     */
    public function __construct(UserInterface $user, CredentialsInterface $credentials, array $badges = [])
    {
       //...
        }
    }
//...
}

La vérification en elle-même dépend d’un écouteur (Listener/Subscriber) qui prend en charge la classe utilisée en second argument du constructeur de la classe passeport.

Qu’est-ce qu’un badge ?

Un badge est un objet qui est ajouté au passeport et qui permet de déclencher des vérifications supplémentaires lors de l’authentification. Par exemple, si l’utilisateur est actif, validation d’un code Yubikey…

Un badge doit implémenter l’interface BadgeInterface qui réclame que la méthode isResolved soit implémentée. Si cette méthode retourne la valeur « faux », l’authentification sera bloquée et l’utilisateur sera redirigé vers la page d’authentification.

Comment sont résolus les badges ?

Pour chaque badge il est nécessaire d’écrire un écouteur de l’événement SymfonyCheckPassportEvent. Ce dernier contient le passeport généré par la méthode authenticate de la classe d’authentification.

L’écouteur doit :

  1. Vérifier la présence dans le passeport du badge qu’il gère.
  2. Réaliser les traitements liés au badge.
  3. Si les conditions sont réunies, marquer le badge comme résolu (pour que la méthode isResolved retourne « vrai ») pour autoriser l’authentification.

Quelles sont les modifications marquantes ?

J’ai surtout dû ajouter beaucoup de classe puis déplacer certaines parties de code présentes dans les classes d’authentification vers les écouteurs.

Quelles sont les modifications apportées aux classes d’authentification ?

La première modification est l’héritage des classes AppLoginAuthenticator et AppTwoFactorAuthenticator qui est passé de SymfonyComponentSecurityGuardAuthenticatorAbstractFormLoginAuthenticator à SymfonyComponentSecurityHttpAuthenticatorAbstractLoginFormAuthenticator.

En observant le nom complet de la classe, il est possible de constater que je suis passé d’une classe d’authentification Guard à une classe d’authentification HTTP.

En suite les deux méthodes getUser et getCredentials on fusionné dans authenticate. La méthode checkCredentials pour la classe d’authentification AppLoginAuthenticator a été simplement supprimée, car c’est l’écouteur fourni par Symfony qui prend le relais pour vérifier le mot de passe de l’utilisateur.

Comment l’utilisateur est redirigé vers la page de saisie du second facteur ?

J’ai ajouté une classe de badge TwoFactorBadge avec son écouteur TwoFactorBadgeSubscriber. Lors de la construction du passeport dans AppLoginAuthenticator, ce badge est ajouté.

<?php

namespace AppSecurity;

final class AppLoginAuthenticator extends AbstractLoginFormAuthenticator
{
    public function authenticate(Request $request): PassportInterface
    {
        $email = $request->get('email');
        $user = $this->userRepository->findOneBy(['email' => $email]);
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $email
        );
        $request->getSession()->set(
            AppTwoFactorAuthenticator::USER_SESSION_KEY,
            $email
        );
        if (!$user) {
            throw new UsernameNotFoundException();
        }

        return new Passport($user, new PasswordCredentials($request->get('password')), [
            // and CSRF protection using a "csrf_token" field
            new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),

            // and add support for upgrading the password hash
            new PasswordUpgradeBadge($request->get('password'), $this->userRepository),
            new TwoFactorBadge(),
        ]);
    }
}

Voir la classe AppLoginAuthenticator complète.

Cet écouteur a une particularité, il doit être exécuté après la vérification du mot de passe. J’ai donc dû modifier la priorité de l’écouteur à -10, car par défaut, les écouteurs sont tous exécutés avant la vérification du mot de passe.

//...
    public static function getSubscribedEvents()
    {
        return [
            CheckPassportEvent::class => ['resolveBadge', -10]
        ];
    }
//...

Maintenant, si le mot de passe est correct, l’écouteur ajoutera la clé need_auth_two avec la valeur « vrai » dans la session sans résoudre le badge.

<?php
namespace AppSecurityListener;
final class TwoFactorBadgeSubscriber implements EventSubscriberInterface
{
    public function resolveBadge(CheckPassportEvent $event)
    {
        /** @var Passport $passport */
        $passport = $event->getPassport();

        // Here I can check if the user has the two factor authentication enabled
        if ($passport->hasBadge(TwoFactorBadge::class) && $passport->hasBadge(PasswordCredentials::class) && $passport->getBadge(PasswordCredentials::class)->isResolved()) {
            $this->session->set('need_auth_two', true);
        }
    }
}

Voir la classe TwoFactorBadgeSubscriber complète.

Après le passage du passeport dans tous les écouteurs, Symfony vérifiera si tous les badges sont résolus. Comme ce ne sera pas le cas, il redirigera l’utilisateur vers la page de login. C’est là que la méthode getLoginUrl de classe d’authentification AppLoginAuthenticator génèrera une URL pour la saisie du code de second facteur d’authentification.

La méthode getLoginUrl n’a pas été modifiée !

<?php

namespace AppSecurity;

final class AppLoginAuthenticator extends AbstractLoginFormAuthenticator
{
//...
    protected function getLoginUrl(Request $request): string
    {
        if ($this->session->get('need_auth_two', false) === true) {
            return $this->urlGenerator->generate(AppTwoFactorAuthenticator::LOGIN_ROUTE);
        }

        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }
//...
}

Comment est vérifié le second facteur ?

Comme avec Guard la page de saisie du code de second facteur est différente de celle de la connexion avec le mot de passe. Il y a donc deux classes d’authentification. J’ai également modifié la classe d’authentification AppTwoFactorAuthenticator.

<?php

namespace AppSecurity;

final class AppTwoFactorAuthenticator extends AbstractLoginFormAuthenticator
{
//...
    public function authenticate(Request $request): PassportInterface
    {
        $email = $request->getSession()->get(self::USER_SESSION_KEY);
        $user = $this->userRepository->findOneBy(['email' => $email]);
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $email
        );
        $request->getSession()->set(
            AppTwoFactorAuthenticator::USER_SESSION_KEY,
            $email
        );
        if (!$user) {
            throw new UsernameNotFoundException();
        }

        return new Passport($user, new TwoFactorCredentials($request->get('password')), [
            // and CSRF protection using a "csrf_token" field
            new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),
            new TwoFactorTimeoutBadge(),
            new TwoFactorMaxAttemptBadge(),

        ]);
    }
}

Cette classe d’authentification appliquait les règles suivantes en plus de la vérification du code :

  • L’utilisateur n’a que 3 essais.
  • L’utilisateur à un temps limité pour saisir le bon code.

Pour chacune de ces règles, j’ai ajouté un badge spécifique au passeport que génère la classe d’authentification. Bien sûr, j’ai également écrit l’écouteur qui correspond et qui marque le badge comme résolu si les conditions sont remplies (TwoFactorMaxAttemptBadgeSubscriber et TwoFactorTimeoutBadgeSubscriber).

Pour la partie vérification du code en lui-même, j’ai ajouté une classe TwoFactorCredentials qui permettra la vérification. Cette classe sera donc utilisée en second argument du constructeur du passeport et contiendra le code saisi par l’utilisateur.

J’ai ajouté une nouvelle classe, car ce n’est pas un mot de passe en tant que tel et je ne souhaite pas que l’écouteur fourni par Symfony se déclenche.

En suite, j’ai écrit l’écouteur pour réaliser la vérification du code.

<?php
namespace AppSecurityListener;
final class TwoFactorCredentialSubscriber implements EventSubscriberInterface
{
//...
    public function checkCredential(CheckPassportEvent $event)
    {
        /** @var Passport $passport */
        $passport = $event->getPassport();
        if ($passport->hasBadge(TwoFactorCredentials::class) === false) {
            return;
        }
        $badge = $passport->getBadge(TwoFactorCredentials::class);
        if ($badge->getPassword() === $this->session->get(AppTwoFactorAuthenticator::CODE_SESSION_KEY, null)) {
            $badge->markResolved();
            return;
        }

        $this->session->set(AppTwoFactorAuthenticator::COUNT_SESSION_KEY,
            $this->session->get(AppTwoFactorAuthenticator::COUNT_SESSION_KEY, 0) + 1);

    }
}

Fichier complet src/Security/Listener/TwoFactorCredentialSubscriber.php

Quelles sont les modifications apportées dans la configuration ?

Étant donné que les classes d’authentification ne sont plus liées à Guard, il a été nécessaire de modifier la configuration.
Ainsi, les ID de service enregistré pour le firewall main dans la clé guard.authenticators ont été déplacés dans la clé custom_authenticators. Étant donné que j’ai deux classes d’authentification, il est obligatoire de désigner le point d’entrée avec la clé entry_point à la place de guard.entry_point.

#...
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            provider: db
            entry_point: AppSecurityAppLoginAuthenticator
            custom_authenticators:
                - AppSecurityAppLoginAuthenticator
                - AppSecurityAppTwoFactorAuthenticator
            logout:
                path: app_logout
#...

Voir le fichier config/packages/security.yaml complet.

En conclusion, quels sont les avantages d’un tel système ?

Le premier avantage que je constate est la possibilité de réutiliser un badge et son écouteur sur plusieurs firewalls de l’application.

Le second est le fort découpage des responsabilités, ainsi qu’une grande facilité d’extension du système.

Enfin le dernier avantage est de pouvoir proposer plus facilement des bundles Symfony permettant d’étendre et mutualiser les badges et leur écouteur.

Et vous,

Dites-moi dans les commentaires quels sont les avantages que vous voyez à cette modification du composant Security de Symfony.

Double authentification avec Symfony

Qu’est-ce que la double authentification ?

Tout le monde connaît l’authentification avec un identifiant et un mot de passe. Cependant, ce système est faillible pour plusieurs raisons :

  • Ils sont souvent les mêmes pour plusieurs sites.
  • Ils sont souvent mal stockés
  • Ils sont souvent trop faciles à trouver
  • Pour les mots de passe forts, les retenir tous est compliqué.

Ainsi, pour augmenter la sécurité lors de l’authentification, il est de plus en plus souvent demandé une seconde preuve que vous êtes bien la personne que vous prétendez être.

C’est la double authentification.

Quand la mettre en place ?

En trois mots : tout le temps. Il y a toujours un usage pirate possible pour toutes les pages protégées par une authentification.
Certains trouveront la réponse extrême. Cependant, pourquoi protéger par un mot de passe quelque chose qui n’a aucune valeur ?

Quels sont les différents types de double authentification ?

Beaucoup connaissent la double authentification avec l’envoi d’un message texte sur votre téléphone portable. Il en existe d’autres :

  • L’utilisation d’une clé physique (USB ou sans fil).
  • L’utilisation d’un code temporaire basé sur le temps.
  • L’utilisation d’un code temporaire envoyé à l’utilisateur selon un moyen que l’utilisateur a choisi (message texte, courriel).
  • L’utilisation d’une authentification via une application mobile liée au service en ligne.

Comment implémenter une double authentification en deux étapes avec Symfony ?

Avant de commencer, nous allons mettre en place une double authentification par l’envoi d’un code temporaire par courriel.
Voici le schéma du dialogue entre le navigateur et les serveurs.

Dialogue Double Authentification

La première authentification via un formulaire est déjà implémentée par Symfony. Cependant, il est nécessaire de personnaliser la vérification du mot de passe via le module Guard.

Dans notre Guard, nous allons stopper l’authentification si le mot de passe est correct et rediriger l’utilisateur vers la page de saisie du second facteur.

Avant la redirection, il est nécessaire de sauvegarder le nom de l’utilisateur en cours de connexion et envoyer un code temporaire sur la boîte courriel de l’utilisateur.

Une fois saisi par l’utilisateur, un autre Guard se chargera de vérifier le code saisi et valider la connexion effective de l’utilisateur.

Simple, non ?

Faisons les courses

Pour mettre en place correctement la double authentification, nous avons besoin de :

  • Sauvegarder le nom de l’utilisateur en cours de connexion.
  • Générer un code et l’associer à l’utilisateur en cours de connexion.
  • Définir un délai de réponse et sauvegarder la valeur limite.
  • Vérifier que l’utilisateur ne teste pas trop de codes (brute force).

Si j’oublie une mesure de sécurité, dites-le moi dans les commentaires.

Ajoutons notre second Guard

La classe AppTwoFactorAuthenticator

<?php declare(strict_types=1);

namespace AppSecurity;

use AppEntityUser;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentHttpFoundationRedirectResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationSessionSessionInterface;
use SymfonyComponentRoutingGeneratorUrlGeneratorInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreExceptionCustomUserMessageAuthenticationException;
use SymfonyComponentSecurityCoreExceptionInvalidCsrfTokenException;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCsrfCsrfToken;
use SymfonyComponentSecurityCsrfCsrfTokenManagerInterface;
use SymfonyComponentSecurityGuardAuthenticatorAbstractFormLoginAuthenticator;
use SymfonyComponentSecurityHttpUtilTargetPathTrait;

final class AppTwoFactorAuthenticator extends AbstractFormLoginAuthenticator
{
    use TargetPathTrait;

    public const LOGIN_ROUTE = 'app_two_factor';

    public const USER_SESSION_KEY = 'two_auth_user';
    public const CODE_SESSION_KEY = 'two_auth_code';
    public const TIMEOUT_SESSION_KEY = 'two_auth_timeout';
    public const COUNT_SESSION_KEY = 'two_auth_count';

    private $entityManager;
    private $urlGenerator;
    private $csrfTokenManager;
    /**
     * @var SessionInterface
     */
    private $session;

    public function __construct(
        EntityManagerInterface $entityManager,
        UrlGeneratorInterface $urlGenerator,
        CsrfTokenManagerInterface $csrfTokenManager,
        SessionInterface $session
    ) {
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->session = $session;
    }

    public function supports(Request $request)
    {
        return self::LOGIN_ROUTE === $request->attributes->get('_route')
            && $request->isMethod('POST');
    }

    public function getCredentials(Request $request)
    {
        return [
            'email' => $request->getSession()->get(self::USER_SESSION_KEY),
            'count' => $request->getSession()->get(self::COUNT_SESSION_KEY, 1),
            'timeout' => $request->getSession()->get(self::TIMEOUT_SESSION_KEY),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) {
            throw new InvalidCsrfTokenException();
        }

        if (time() > $credentials['timeout']) {
            throw new TwoFactorTimedoutException();
        }

        if ($credentials['count'] >= 3) {
            throw new TwoFactorMaxAttemptReachedException();
        }

        $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);

        if (!$user) {
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('Email could not be found.');
        }

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        if ($credentials['password'] === $this->session->get(self::CODE_SESSION_KEY, null)) {
            return true;
        }

        $this->session->set(self::COUNT_SESSION_KEY, $credentials['count'] + 1);

        return false;
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        $request->getSession()->remove('need_auth_two');
        $request->getSession()->remove(self::USER_SESSION_KEY);
        $request->getSession()->remove(self::CODE_SESSION_KEY);
        $request->getSession()->remove(self::TIMEOUT_SESSION_KEY);
        $request->getSession()->remove(self::COUNT_SESSION_KEY);

        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse('/');
    }

    protected function getLoginUrl()
    {
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }
}

La constante LOGIN_ROUTE contient le nom de la route dédiée à ce Guard. Le contrôleur doit être défini, nous le verrons plus bas.

Cette classe définit 4 constantes qui permettront de stocker les informations utiles dans la session. Vous pouvez tout à fait sauvegarder ces informations en base de données.

Activer le second Guard

Dans le fichier config/packages/security.yaml, ajouter le nom complet de la classe dans la liste des authenticators :

#[...]
    firewalls:
        main:
            guard:
                authenticators:
                    - AppSecurityAppLoginAuthenticator
                    - AppSecurityAppTwoFactorAuthenticator
                entry_point: AppSecurityAppLoginAuthenticator

Maintenant, Symfony a besoin de connaître le Guard principal. Ajouter la clé entry_point avec comme valeur le nom complet de la classe du Guard gérant la connexion par identifiant et mot de passe.

Ajouter le contrôleur

Maintenant, ajouter le contrôleur lié au Guard du second facteur. Ce contrôleur se comporte comme celui du Guard de l’authentification par identifiant et mot de passe avec une différence. Il n’est pas possible de modifier l’utilisateur.

Voici un exemple de la méthode contrôleur :

//Fichier : src/Controller/SecurityController.php

    /**
     * @Route("/two_factor", name="app_two_factor")
     */
    public function twoFactor(SessionInterface $session, CodeGeneratorInterface $codeGenerator, AuthenticationUtils $authenticationUtils): Response
    {
        $error = $authenticationUtils->getLastAuthenticationError();
        if ($session->get(AppTwoFactorAuthenticator::CODE_SESSION_KEY) === null) {
            $error = null;
            $session->set(AppTwoFactorAuthenticator::CODE_SESSION_KEY, $codeGenerator->generate());
            $session->set(AppTwoFactorAuthenticator::TIMEOUT_SESSION_KEY, time() + (60 * 5));
            $session->set(AppTwoFactorAuthenticator::COUNT_SESSION_KEY, 1);
            //Send here the code by email.
        }
        return $this->render('security/two_factor.html.twig', ['error' => $error]);
    }

Ici, nous retrouvons le nom de la route définie dans le Guard pour la double authentification.

Le rôle du contrôleur est d’afficher les erreurs de saisie du code et si le code n’existe pas, il l’initialise et l’envoie par courriel.

Le fichier Twig lié ressemble à ceci :

{% extends 'base.html.twig' %}

{% block title %}
Two factor auth
{% endblock %}

{% block body %}
    <form method="post">
        {% if error %}
            <div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
        {% endif %}

        <h1 class="h3 mb-3 font-weight-normal">Please confirm your identity</h1>
        <label for="inputPassword">Password</label>
        <input type="password" name="password" id="inputPassword" class="form-control" required>

        <input type="hidden" name="_csrf_token"
               value="{{ csrf_token('authenticate') }}"
        >
        <button class="btn btn-lg btn-primary" type="submit">
            Send code
        </button>
    </form>
{% endblock %}

Activer la double authentification

La seconde authentification est presque prête. Cependant, il n’est pas possible de l’utiliser. Pour l’utiliser, il est nécessaire de modifier la classe Guard liée à l’authentification par utilisateur et mot de passe.

La première modification consiste à indiquer que l’authentification a échoué dans tous les cas. Nous allons cependant indiquer qu’il faut rediriger vers le second facteur d’authentification grâce à une information stockée en session.

Voici le code de la méthode liée à la vérification du mot de passe :

// Fichier : src/Security/AppLoginAuthenticator.php
    public function checkCredentials($credentials, UserInterface $user)
    {
        if ($this->encoder->getEncoder($user)->isPasswordValid($user->getPassword(), $credentials['password'], null)) {
            $this->session->set('need_auth_two', true);
            return false;
        }
        return false;
    }

Maintenant que l’authentification échoue systématiquement, comment renvoyer l’utilisateur ayant saisi son mot de passe correct vers la double authentification ?

Cela se passe dans la fonction getLoginUrl du Guard

// Fichier : src/Security/AppLoginAuthenticator.php
    protected function getLoginUrl()
    {
        if ($this->session->get('need_auth_two', false) === true) {
            return $this->urlGenerator->generate(AppTwoFactorAuthenticator::LOGIN_ROUTE);
        }
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }

Dans le cas où la session contient la clé need_auth_two et que sa valeur est à vrai, alors l’URL retournée est celle correspondant à la page de l’authentification à deux facteurs.

Éviter la réutilisation du code ou la mauvaise redirection

Avec le code tel qu’il est actuellement, il est possible d’être redirigé vers la page de la double authentification alors que le mot de passe est erroné.

Il est également possible de réutiliser un code déjà utilisé si la session n’est pas complètement renouvelée lors de la déconnexion.

Pour éviter ces mauvais effets, nous allons réinitialiser le code et la demande de double authentification lors de la récupération de l’identifiant et du mot de passe saisis par l’utilisateur.

Voici donc le contenu de la méthode getCredentials du Guard AppLoginAuthenticator :

// Fichier : src/Security/AppLoginAuthenticator.php
    public function getCredentials(Request $request)
    {
        $credentials = [
            'email' => $request->request->get('email'),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['email']
        );
        $request->getSession()->set(
            AppTwoFactorAuthenticator::USER_SESSION_KEY,
            $credentials['email']
        );

        $request->getSession()->set(AppTwoFactorAuthenticator::CODE_SESSION_KEY, null);
        $request->getSession()->set('need_auth_two', false);

        return $credentials;
    }

C’est également ici que nous sauvegardons le nom d’utilisateur saisi pour être utilisé lors de la double authentification.

Conclusion

La double authentification est maintenant prête à minima. Il reste encore quelques améliorations telles que :

  • Utiliser un événement pour déclencher la génération du code et son envoi.
  • Permettre le changement d’utilisateur lors de la double authentification.

Mais cela fera peut-être l’objet d’un autre billet de blog.

Dites-moi dans les commentaires comment vous avez implémenté la double authentification sur vos projets. Je suis à votre service si vous avez des questions.

PS J’ai utilisé ce projet pour écrire ce billet de blog.

Les navigateurs ont-ils fait évoluer le niveau de sécurité de leur gestionnaire de mot de passe ?

Dans ce billet de blogue, je vais vous parler de mot de passe et de gestionnaires de mots de passe qui permettent de les conserver tous au même endroit.

Vous avez surement eu l’occasion d’entendre parler des mots de passe. Ces suites de caractères que nous devons saisir pour nous authentifier sur les sites Web (et autre application ou ordinateurs) que nous visitons.
Vous avez peut-être entendu parler également des gestionnaires de mot de passe ; ces logiciels spécialisés dans la gestion et la synchronisation de vos informations sensibles (identifiant, mot de passe, carte bleue, etc.).

Nos navigateurs Web intègrent eux aussi un gestionnaire de données personnelles sensibles (identifiant/mot de passe, carte bleue, adresse postale, saisie courante), mais qu’en est-il de la protection de nos données par défaut ?

J’ai réalisé un petit test sur la gestion des mots de passe uniquement sur différent système d’exploitation et différent navigateur. Côté navigateur voici la liste retenue :

  • Firefox de la fondation Mozilla.
  • Chromium la base libre d’un grand nombre de navigateurs (Google + la communauté).
  • Google Chrome, le navigateur de Google basé sur Chromium.
  • Opera, un navigateur basé également sur Chomium et édité par Opera Software.
  • Brave, un navigateur basé également sur Chomium et édité par Brave Software qui met l’accent sur le respect de la vie privée.
  • Tor Brower, un navigateur basé sur Firefox et orienté sur l’anonymisation de la navigation et le respect de la vie privée.

Le premier test a été réalisé sur Linux via la distribution Ubuntu en version 19.04. Le second a été réalisé sur Windows 10 (1903) enfin le dernier a été réalisé sur macOS (10.13.6).

Voici le résumé de la situation.

Tous les navigateurs intègrent un outil pour la gestion des mots de passe. Cependant seul Tor Browser le bloque complètement.

Unable to change Marger Password.
Erreur affiché lors de la définition d’un mot de passe maître sur Tor Browser

Les mots de passe sont donc par défaut stocké chiffré sur le disque dur avec une clé non protégés par un mot de passe. Étant donné que la sécurité n’est pas dans les algorithmes, trouver l’emplacement de la clé et pouvoir déchiffrer les mots de passe sera donc possible.

Il est donc important de pouvoir verrouiller ce coffre-fort numérique. Sur Linux, Firefox est les seuls à proposer une solution.

Paramètre par défaut de Firefox pour la gestion des identifiants de connexion.

Les navigateurs basés sur Chromium ne proposent rien (ai-je mal cherché ?) pour Linux.

Sur Windows et macOS, Firefox propose les mêmes options, mais les navigateurs basés sur Chromium utilisent le mot de passe du compte local pour protéger votre coffre-fort.

Chrome sur macOs demande me mot de passe du compte pour afficher un mot de passe sauvegardé.

C’est déjà mieux tant que vous avez défini un mot de passe pour votre compte sur votre ordinateur. Si ce n’est pas le cas, je vous conseille vivement de le faire.

J’ai noté une petite particularité sur Safari, même avec un compte sans mot de passe, un mot de passe vide est réclamé pour accéder à la liste des mots de passe enregistrés.

Safari sur macOs demande un mot de passe pour afficher les informations sauvegardées même si le mot de passe est vide.

En conclusion, la situation sur les gestionnaires de mot de passe des navigateurs n’a pas changé depuis que j’ai décidé de désactiver toutes les fonctionnalités de gestions de mot de passe, carte bleue et saisie semi-automatique de mes navigateurs. Continuerait donc d’utiliser un vrai gestionnaire de mot de passe et je vous conseille de faire de même.

Voici quelques exemples :

Et vous, comment configurez-vous votre navigateur ? Ai-je oublié quelque chose dans mon comparatif ? Si votre navigateur préféré n’est pas dans la liste, donnez-moi son nom dans les commentaires pour que je regarde.

Retrospective de l’année 2018

L’année 2018 a été riche en évènements autant dans l’actualité que dans mes domaines préférés tels que la sécurité de l’information et mon langage de programmation préféré ; qui est PHP.

Ainsi la documentation française de PHP a connu une nette amélioration dont toute la communauté francophone profite !

Merci aux nombreux contributeurs traducteurs et relecteurs qui soumettent chaque semaine de nouvelles traductions et corrections.

Je vous invite à nous rejoindre pour mettre à jour la traduction, corriger les fautes pour améliorer en permanence la qualité de la documentation française.

Pour cela, un petit tutoriel vidéo avait été réalisé :

Content not available.
Please allow cookies by clicking Accept on the banner

Pour ce qui est de la sécurité de l’information, la mise en application du Réglement Général pour la Protection des Données (RGPD) fût l’évènement majeur de cette année et pour certain une prise de conscience sur les traitements réalisés par les entreprises.

Je me rends compte tous les jours qu’en question de sécurité de l’information, personne n’est épargné. Même la petite association qui dispose d’un site internet peut être victime des pirates.

La rétrospective réalisée par Zataz doit servir à prendre conscience des dangers d’internet et à se poser les bonnes questions. Ai-je réellement besoin d’étaler ma vie sur les réseaux sociaux ? Et par conséquent la vie des personnes qui m’entoure ?

Je vous souhaite en cette nouvelle année une bonne protection de vos données personnelles et une prise de conscience sur le contrôle de vos données.

Tous mes meilleurs voeux pour 2019 !

La sécurité informatique n’est pas pour vous ?

« De toute façon, mes données n’intéressent personne »… FAUX ! Vos données intéressent toujours quelqu’un pour soutirer de l’argent !

D’autre part, le titre de cet article est faux, voici le titre corrigé :
« La sécurité informatique de vos informations personnelles n’est pas pour vous ? »

Voici deux vidéos qui pourraient bien vous faire changer d’avis :

Content not available.
Please allow cookies by clicking Accept on the banner
Com’Infinie – Et si un voyant vous révélait les dangers d’Internet
Content not available.
Please allow cookies by clicking Accept on the banner
Campagne Hack Academy – JENNY

Comment se prémunir ? En adoptant une hygiène informatique pour se prémunir des risques majeurs.

Pour tout le monde, ce guide est utile à la maison comme au travail :

https://www.ssi.gouv.fr/particulier/guide/guide-des-bonnes-pratiques-de-linformatique/

Pour ceux qui voyagent (même occasionnellement) :

https://www.ssi.gouv.fr/particulier/guide/partir-en-mission-avec-son-telephone-sa-tablette-ou-son-ordinateur-portable/

Vous souhaitez aller plus loin ? Formez-vous ! Je vous recommande cette formation en ligne gratuite ne nécessitant aucune connaissance technique (disponible jusqu’en avril 2021).

Et vous ? Faites-vous réellement attention à ce genre de chose pour vous, vos enfants, vos ainés ?

Mise à jour : Modification de la date de fin de disponibilité du Mooc.