blacklist.class.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. // Vérification de l'existence de la clé HTTP_HOST avant utilisation
  52. $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'undefined';
  53. // Ajout d'un journal pour les cas où HTTP_HOST est manquant
  54. if ($host != 'undefined') {
  55. $isDev = (strpos($_SERVER['HTTP_HOST'], 'local.') === 0); // Vérifie si c'est une URL locale de développement
  56. return $isDev ? TRUE : filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== FALSE;
  57. } else {
  58. return FALSE;
  59. }
  60. }
  61. /**
  62. * Récupère l'URL complète de la requête.
  63. *
  64. * @return string L'URL complète.
  65. */
  66. private static function getFullUrl() {
  67. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
  68. return $protocol . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
  69. }
  70. /**
  71. * Vérifie si l'extension de l'URL est blacklistée.
  72. *
  73. * @return bool TRUE si l'extension est blacklistée, FALSE sinon.
  74. */
  75. private static function isBlacklistExtention() {
  76. $uri = $_SERVER['REQUEST_URI'];
  77. $blackListExtention = ['php'];
  78. $extension = pathinfo(parse_url($uri, PHP_URL_PATH), PATHINFO_EXTENSION);
  79. return in_array(strtolower($extension), $blackListExtention);
  80. }
  81. /**
  82. * Lit les tentatives existantes depuis le fichier de log.
  83. *
  84. * @return array Un tableau des tentatives.
  85. */
  86. private static function readBlacklist() {
  87. $attempts = [];
  88. if (file_exists(self::$log_file)) {
  89. $lines = file(self::$log_file, FILE_IGNORE_NEW_LINES);
  90. foreach ($lines as $line) {
  91. list($ip, $timestamp) = explode(',', $line);
  92. $attempts[] = ['ip' => $ip, 'timestamp' => strtotime($timestamp)];
  93. }
  94. }
  95. return $attempts;
  96. }
  97. /**
  98. * Vérifie si une IP est déjà blacklistée.
  99. *
  100. * @param string $_ip L'adresse IP à vérifier.
  101. * @return bool TRUE si l'IP est blacklistée, FALSE sinon.
  102. */
  103. private static function checkBlacklist(string $_ip) {
  104. $blacklisted = FALSE;
  105. if (file_exists(self::$blacklist_file)) {
  106. $blacklisted_ips = file(self::$blacklist_file, FILE_IGNORE_NEW_LINES);
  107. $blacklisted = in_array($_ip, $blacklisted_ips);
  108. }
  109. return $blacklisted;
  110. }
  111. /**
  112. * Ajoute une tentative pour une IP dans le fichier de log.
  113. *
  114. * @param string $_ip L'adresse IP à ajouter.
  115. * @return void
  116. */
  117. private static function addBlacklist(string $_ip) {
  118. file_put_contents(self::$log_file, "$_ip," . date('Y-m-d H:i:s') . ", " . $_SERVER["REQUEST_METHOD"] . "," . self::getFullUrl() . "\n", FILE_APPEND);
  119. }
  120. /**
  121. * Vérifie si une IP doit être blacklistée et effectue les actions nécessaires.
  122. *
  123. * @return array|null Retourne un tableau d'erreur ou NULL si aucune action n'est nécessaire.
  124. */
  125. private static function check() {
  126. if (self::isBlacklistExtention()) {
  127. $now = time();
  128. $time_window = self::$time_window;
  129. $attempts = self::readBlacklist();
  130. $ip = $_SERVER['REMOTE_ADDR'];
  131. // Vérifie si l'IP est déjà blacklistée
  132. $blacklisted = self::checkBlacklist($ip);
  133. // Ajoute une tentative
  134. self::addBlacklist($ip);
  135. // Filtre les tentatives récentes
  136. $recent_attempts = array_filter($attempts, function ($attempt) use ($ip, $now, $time_window) {
  137. return $attempt['ip'] === $ip && ($now - $attempt['timestamp']) <= $time_window;
  138. });
  139. // Si trop de tentatives, ajoute l'IP à la blacklist
  140. if (count($recent_attempts) + 1 > self::$max_attempts && !$blacklisted) {
  141. file_put_contents(self::$blacklist_file, "$ip\n", FILE_APPEND);
  142. $blacklisted = true;
  143. }
  144. // Redirection si blacklisté
  145. if ($blacklisted) {
  146. header("HTTP/1.1 403 Forbidden");
  147. header("Location: /noAccess.php");
  148. exit();
  149. } else {
  150. return ["error" => 404, "text" => "La page que vous cherchez n'existe pas."];
  151. }
  152. } else {
  153. return ["error" => 404, "text" => "La page que vous cherchez n'existe pas."];
  154. }
  155. }
  156. /**
  157. * Vérifie si l'utilisateur actuel est blacklisté.
  158. *
  159. * @return void
  160. */
  161. public static function itIs() {
  162. if (self::checkBlacklist($_SERVER['REMOTE_ADDR'])) {
  163. header("Location: /noAccess.php");
  164. exit();
  165. }
  166. return NULL;
  167. }
  168. }