src/Event/ForceBruteListener.php line 169

Open in your IDE?
  1. <?php
  2. namespace App\Event;
  3. use Symfony\Component\HttpFoundation\Response;
  4. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  5. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  6. use Symfony\Component\Security\Core\Security;
  7. // use Symfony\Bundle\FrameworkBundle\Routing\Router;
  8. // use Symfony\Component\HttpFoundation\RedirectResponse;
  9. use App\PaaBundle\Entity\adressesIP ;
  10. use App\PaaBundle\Entity\adressesIP_Evenements ;
  11. use App\PaaBundle\Component\Logs;
  12. use DateTime;
  13. // Gestionnaire de page not found, pour blacklistage des attaques par force brute
  14. // Erreurs NotFoundHttpException : test par un robot de toutes les URLS classiques
  15. // Erreurs d'authentification (A VENIR)
  16. class ForceBruteListener {
  17.     /**
  18.      * @var string
  19.      */
  20.     private $project_dir;
  21.     private $entityManager;
  22.     private $security;
  23.     public function __construct($project_dir$doctrineSecurity $security) {
  24.         $this->project_dir $project_dir;
  25.         $this->entityManager $doctrine->getManager() ;
  26.         $this->security $security ;
  27.     }
  28.     // Capture des exceptions "page not found"
  29.     public function onKernelException(GetResponseForExceptionEvent $event) {
  30.         if (
  31. //            $_ENV['APP_ENV'] != 'prod' || 
  32.             !$event->isMasterRequest() || 
  33.             !$event->getException() instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
  34.         ) {
  35.             // Nous ne sommes pas en prod, ou ce n'est pas la requête ppale, ou ce n'est pas une exception "File not found"
  36.             return;
  37.         }
  38.         // A partir de là, on traite les exceptions "Page non trouvée"
  39.         $request $event->getRequest() ;
  40.         
  41.         if ($request->getRequestUri() == "/favicon.ico") {
  42.             // Pas à pendre en compte : arrive toujours en prod
  43.             return ;
  44.         }
  45.         if ($this->security->getToken()) {
  46.             // Cette condition ne semble jamais respectée et c'est dommage car on ne peut pas savoir si le user est authentifié
  47.             // et que dans ce cas on ne devrait pas bannir cette adresse IP car l'erreur "Route not found" est plus probablement due à un bug de l'application (route bosolète/mal configurée/...)
  48.             // Du coup, on est obligés de passer par la vérification que cette IP a été authentifiée au moins une fois dans le passé ci-dessous ($loAdresseIP->estAuthentifiéeAuMoinsUneFois())
  49.             // C'est src/PaaBundle/Component/Authentication/Handler/LoginSuccessHandler.php qui pose le flag en question
  50.             $user $this->security->getUser();
  51.             // L'objet sécurité est à jour avec le token d'authentification, on peut donc vérifier si l'utilisateur en cours est bien authentifié
  52.             // $user = $this->security->getUser();
  53.             $lbAuthentifié $this->security->isGranted('IS_AUTHENTICATED_FULLY') ;
  54.             if ($lbAuthentifié) {
  55.                 // Puisque l'utilisateur est authentifié, on ne devrait pas le bannir s'il s'agit d'un bug de l'application et non d'une tentative de force brute
  56.                 return ;
  57.             }
  58.         }
  59.         $ip $request->getClientIp() ;
  60.         $loRepo $this->entityManager->getRepository("PaaBundle:adressesIP");
  61.         if (!$loRepo->estUtilisable()) {
  62.             // La table AdressesIP n'est pas encore créée
  63.             return ;
  64.         }
  65.         $loAdresseIP $loRepo->findByIP($ip) ;
  66.         if (!$loAdresseIP) {
  67.             // Adresse IP pas encore référencée : l'ajouter maintenant
  68.             $loAdresseIP = new adressesIP() ;
  69.             $loAdresseIP->setCIP($ip) ;
  70.         } else if ($loAdresseIP->estAuthentifiéeAuMoinsUneFois()) {
  71.             // Cette adresse a déja été authentifiée au moins une fois (un utilisateur s'est authentifié avec succès à partir de cette adresse)
  72.             // On ne va pas bannir cette adresse IP car l'erreur "Route not found" est plus probablement due à un bug de l'application (route bosolète/mal configurée/...)
  73.             return ;
  74.         }
  75.         // Ajouter l'événement à l'historique de cette adresse IP
  76.         $loEvenement = new adressesIP_Evenements() ;
  77.         $loEvenement->setAdresseIP($loAdresseIP) ;
  78.         $loEvenement->setTEvenement(new DateTime()) ;
  79.         $loEvenement->setITypeEvenement($loRepo::TYPE_ROUTENOTFOUND) ;
  80.         $loEvenement->setCDescEvenement($request->getRequestUri()) ;
  81.         $this->entityManager->persist($loEvenement) ;
  82.         $this->entityManager->flush() ;
  83. // LG 20241023 début
  84. //        $lbBanni = $loRepo->updateABannir($loAdresseIP) ;
  85.         $lbVientDetreBannie false ;
  86.         $lbBanni $loRepo->updateABannir($loAdresseIP$lbVientDetreBannie) ;
  87. // LG 20241023 fin
  88.         if ($lbBanni) {
  89.             // Cette adresse est bannie
  90. // LG 20241023 début
  91. //            // Logger le banissement
  92. //            $message = "L'adresse IP $ip vient d'être bannie pour dépassement du nombre max d'événements.";
  93. //            $this->log($message) ;
  94.             if ($lbVientDetreBannie) {
  95.                 // Logger le banissement
  96.                 $message "L'adresse IP vient d'être bannie pour dépassement du nombre max d'événements : $ip.";
  97.                 $this->log($message) ;
  98.             }
  99. // LG 20241023 fin
  100.             // Renvoyer une réponse ici évite de passer dans les gestionnaires d'erreur suivants : c'est donc cette réponse qui sera renvoyée au client
  101.             $response = new Response($this->getMsg($ip), Response::HTTP_FORBIDDEN);
  102.             $event->setResponse($response);
  103.             return ;
  104.         }
  105.         // Si on arrive jusque là, le traitement normal de l'exception va se poursuivre
  106.         return ;
  107.     }
  108.     // Vérification sur chaque requête que l'adresse n'est pas bannie
  109.     public function onKernelController(FilterControllerEvent $event) {
  110.         if (!$event->isMasterRequest()) {
  111.             // Cette requête n'est pas la requête principale
  112.             return ;
  113.         }
  114.         // if ($event->getController() && isset($event->getController()[1]) && isset($event->getController()[1]) == "toolbarAction") {
  115.         //     // Rien à faire dans ce contexte
  116.         //     return ;
  117.         // }
  118.         if ($this->security->getToken()) {
  119.             // L'objet sécurité est à jour avec le token d'authentification, on peut donc vérifier si l'utilisateur en cours est bien authentifié
  120.             // $user = $this->security->getUser();
  121.             $lbAuthentifié $this->security->isGranted('IS_AUTHENTICATED_FULLY') ;
  122.             if ($lbAuthentifié) {
  123.                 // Puisque l'utilisateur est authentifié, pas besoin de vérifier s'il est banni
  124.                 return ;
  125.             }
  126.         }
  127.         $request $event->getRequest() ;
  128.         $ip $request->getClientIp() ;
  129.         $loRepo $this->entityManager->getRepository("PaaBundle:adressesIP");
  130.         if (!$loRepo->estUtilisable()) {
  131.             // La table AdressesIP n'est pas encore créée
  132.             return ;
  133.         }
  134.         $loAdresseIP $loRepo->findByIP($ip) ;
  135.         if ($loAdresseIP && $loAdresseIP->estBannie()) {
  136.             // Cette adresse IP est bannie
  137.             // Logger la tentative
  138. // LG 20241023 début
  139. //            $message = "L'adresse IP est bannie mais fait une tentative d'accès : $ip.";
  140.             $message "L'adresse IP est bannie mais fait une tentative d'accès : $ip, URI : {$event->getRequest()->getRequestUri()}.";
  141. // LG 20241023 fin
  142.             $this->log($message) ;
  143.             // Terminer en erreur
  144.             throw new \Exception($this->getMsg($ip)) ;
  145.         }
  146.         // Si on arrive jusque là, le traitement normal va se poursuivre
  147.         return ;
  148.     }
  149.     // Renvoyer le message d'erreur
  150.     private function getMsg($ip) {
  151.         return "Désolé, l'adresse IP que vous utilisez ($ip) a été bannie pour cette application en raison d'un trop grand nombre de tentatives infructueuses. Merci de demander à un administrateur de vous aider à rétablir la situation." ;
  152.     }
  153.     // Logguer un message
  154.     private function log($msg) {
  155.         Logs::setProjectDir($this->project_dir) ;
  156.         Logs::setStackTrace("") ;
  157.         Logs::critical($msg, [], true) ;
  158.     }
  159. }