blacklist.class.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <?php
  2. /**
  3. * Classe `blacklist`
  4. *
  5. * Cette classe gère la mise en liste noire des adresses IP en fonction des tentatives
  6. * répétées d'accès à des ressources protégées. Elle permet de :
  7. * - Suivre les tentatives d'accès via un fichier de log.
  8. * - Blacklister les adresses IP après un certain nombre de tentatives.
  9. * - Vérifier si une adresse IP est blacklistée.
  10. * - Gérer les extensions d'URL interdites.
  11. */
  12. class blacklist {
  13. /**
  14. * Fichier de log des tentatives.
  15. *
  16. * @var string
  17. */
  18. private static $log_file = '../blacklist/ip_attempts.log';
  19. /**
  20. * Fichier contenant les IP blacklistées.
  21. *
  22. * @var string
  23. */
  24. private static $blacklist_file = '../blacklist/ip.txt';
  25. /**
  26. * Nombre maximum de tentatives autorisées avant blacklist.
  27. *
  28. * @var int
  29. */
  30. private static $max_attempts = 5;
  31. /**
  32. * Fenêtre de temps pour les tentatives (en secondes).
  33. *
  34. * @var int
  35. */
  36. private static $time_window = 10 * 60; // 10 minutes en secondes
  37. /**
  38. * Exécute la vérification de la blacklist.
  39. *
  40. * @return array|null Retourne un tableau d'erreur ou NULL si aucune action n'est nécessaire.
  41. */
  42. public static function execute() {
  43. return self::check();
  44. }
  45. /**
  46. * Vérifie si l'adresse IP est une IPv4 valide.
  47. *
  48. * @return bool TRUE si l'adresse IP est valide, FALSE sinon.
  49. */
  50. public static function isValidIPv4() {
  51. $isDev = (strpos($_SERVER['HTTP_HOST'], 'local.') === 0); // Vérifie si c'est une URL locale de développement
  52. return $isDev ? TRUE : filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== FALSE;
  53. }
  54. /**
  55. * Récupère l'URL complète de la requête.
  56. *
  57. * @return string L'URL complète.
  58. */
  59. private static function getFullUrl() {
  60. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
  61. return $protocol . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
  62. }
  63. /**
  64. * Vérifie si l'extension de l'URL est blacklistée.
  65. *
  66. * @return bool TRUE si l'extension est blacklistée, FALSE sinon.
  67. */
  68. private static function isBlacklistExtention() {
  69. $uri = $_SERVER['REQUEST_URI'];
  70. $blackListExtention = ['php'];
  71. $extension = pathinfo(parse_url($uri, PHP_URL_PATH), PATHINFO_EXTENSION);
  72. return in_array(strtolower($extension), $blackListExtention);
  73. }
  74. /**
  75. * Lit les tentatives existantes depuis le fichier de log.
  76. *
  77. * @return array Un tableau des tentatives.
  78. */
  79. private static function readBlacklist() {
  80. $attempts = [];
  81. if (file_exists(self::$log_file)) {
  82. $lines = file(self::$log_file, FILE_IGNORE_NEW_LINES);
  83. foreach ($lines as $line) {
  84. list($ip, $timestamp) = explode(',', $line);
  85. $attempts[] = ['ip' => $ip, 'timestamp' => strtotime($timestamp)];
  86. }
  87. }
  88. return $attempts;
  89. }
  90. /**
  91. * Vérifie si une IP est déjà blacklistée.
  92. *
  93. * @param string $_ip L'adresse IP à vérifier.
  94. * @return bool TRUE si l'IP est blacklistée, FALSE sinon.
  95. */
  96. private static function checkBlacklist(string $_ip) {
  97. $blacklisted = FALSE;
  98. if (file_exists(self::$blacklist_file)) {
  99. $blacklisted_ips = file(self::$blacklist_file, FILE_IGNORE_NEW_LINES);
  100. $blacklisted = in_array($_ip, $blacklisted_ips);
  101. }
  102. return $blacklisted;
  103. }
  104. /**
  105. * Ajoute une tentative pour une IP dans le fichier de log.
  106. *
  107. * @param string $_ip L'adresse IP à ajouter.
  108. * @return void
  109. */
  110. private static function addBlacklist(string $_ip) {
  111. file_put_contents(self::$log_file, "$_ip," . date('Y-m-d H:i:s') . ", " . $_SERVER["REQUEST_METHOD"] . "," . self::getFullUrl() . "\n", FILE_APPEND);
  112. }
  113. /**
  114. * Vérifie si une IP doit être blacklistée et effectue les actions nécessaires.
  115. *
  116. * @return array|null Retourne un tableau d'erreur ou NULL si aucune action n'est nécessaire.
  117. */
  118. private static function check() {
  119. if (self::isBlacklistExtention()) {
  120. $now = time();
  121. $time_window = self::$time_window;
  122. $attempts = self::readBlacklist();
  123. $ip = $_SERVER['REMOTE_ADDR'];
  124. // Vérifie si l'IP est déjà blacklistée
  125. $blacklisted = self::checkBlacklist($ip);
  126. // Ajoute une tentative
  127. self::addBlacklist($ip);
  128. // Filtre les tentatives récentes
  129. $recent_attempts = array_filter($attempts, function ($attempt) use ($ip, $now, $time_window) {
  130. return $attempt['ip'] === $ip && ($now - $attempt['timestamp']) <= $time_window;
  131. });
  132. // Si trop de tentatives, ajoute l'IP à la blacklist
  133. if (count($recent_attempts) + 1 > self::$max_attempts && !$blacklisted) {
  134. file_put_contents(self::$blacklist_file, "$ip\n", FILE_APPEND);
  135. $blacklisted = true;
  136. }
  137. // Redirection si blacklisté
  138. if ($blacklisted) {
  139. header("HTTP/1.1 403 Forbidden");
  140. header("Location: /noAccess.php");
  141. exit();
  142. } else {
  143. return ["error" => 404, "text" => "La page que vous cherchez n'existe pas."];
  144. }
  145. } else {
  146. return ["error" => 404, "text" => "La page que vous cherchez n'existe pas."];
  147. }
  148. }
  149. /**
  150. * Vérifie si l'utilisateur actuel est blacklisté.
  151. *
  152. * @return void
  153. */
  154. public static function itIs() {
  155. if (self::checkBlacklist($_SERVER['REMOTE_ADDR'])) {
  156. header("Location: /noAccess.php");
  157. exit();
  158. }
  159. return NULL;
  160. }
  161. }