Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Non-Officiels > Site Web > PHP > Optimisation & Sécurité > Lecture du tutoriel

Un bot anti-defacing

Auteur : Seb-D
Créé : le 07/12/2006 01:09:24
Modifié : le 15/05/2008 18:42:05
Noter et commenter ce tutoriel
Imprimer ce tutoriel
Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
Il arrive très régulièrement que des sites Internet soient piratés. Dans ce tutoriel, nous allons réfléchir sur la mise en place d'une solution efficace et facile d'accès pour nos sites web, de manière à se prémunir contre ces attaques qui peuvent être furtives et difficilement décelables.

Cette solution consiste à créer un robot écrit en PHP qui vérifiera qu'aucun pirate n'est venu modifier vos fichiers.
Sommaire du chapitre :

Première approche

Nous n'aborderons pas ici les différentes méthodes pour sécuriser le code PHP de vos scripts. Cependant, je vous invite à lire les différents tutoriels qui trainent sur le web. Il ne faut pas oublier que les principales causes de piratage de nos sites web sont les failles présentes dans nos sources PHP.


Afin de comprendre l'intérêt d'un tel bot, imaginons le scénario suivant.

Votre site internet contient un espace membre. Un pirate est parvenu à modifier les pages de votre site web et à chaque fois qu'un utilisateur s'identifie dans la zone membre, un e-mail, contenant les informations de cet utilisateur (login, password, email, etc.), est envoyé au pirate.

Voici la question que je vais alors vous poser :

Comment détecter ce piratage, sachant que dans ce scénario, l'aspect visuel de votre page d'identification n'a pas changé ?

Réfléchissons...

Comme vous avez pu le comprendre, il est presque impossible de détecter ce genre de piratage, du moins manuellement. Quand un site est en place, on réouvre rarement les fichiers sources pour vérifier que rien n'a été modifié.

Alors, comment automatiser la vérification de vos sources ? Qu'est-ce qui permettrait de vérifier qu'un fichier n'a pas été modifié ?


Il y a bien entendu plusieurs méthodes possibles. Nous allons nous intéresser à celle qui me semble la plus facile à mettre en place : la vérification du hash MD5 du fichier.

Le hash MD5 d'un fichier est unique : si un fichier est modifié, son hash MD5 le sera lui aussi.
Il devient donc simple de vérifier si l'un de vos fichiers n'a pas été modifié : il suffit de comparer le hash MD5 actuel du fichier avec celui qu'il est censé avoir.

Nous aurions aussi pu utiliser un autre algorithme tel que le SHA1. Certains le jugent plus fiable, mais après plusieurs benchmarks, je me suis rendu compte que PHP met deux fois plus de temps pour calculer un hash SHA1 qu'un hash MD5.

Pour réaliser le bot, PHP nous fournit une fonction qui va nous être très utile : la fonction md5_file($filename).


Le fonctionnement est donc très simple : il suffit de comparer le md5 d'un fichier obtenu grâce à la fonction énoncée plus haut avec la chaîne md5 que le fichier est censé avoir, que l'on stockera dans une base de données MySQL.
Si les chaînes ne sont pas identiques, c'est que le fichier aura subi une modification.

Une fois le code source du bot écrit, il suffira de l'exécuter toutes les heures via un site comme webcron.org, ou directement via le crontab de votre serveur.

Architecture de la table MySQL

Nous allons avoir recours à une table MySQL, qui contiendra la liste des fichiers à vérifier et leur hash MD5.

Voici la structure de la table



bot_fichiers



NomType
file_id integer(11)
path varchar(255)
hash varchar(32)


Et la requête SQL...



Code : SQL
1
2
3
4
5
6
CREATE TABLE `bot_fichiers` (
  `file_id` int(11) NOT NULL auto_increment,
  `path` varchar(255) NOT NULL,
  `hash` varchar(32) NOT NULL,
  PRIMARY KEY  (`file_id`)
) ENGINE=MyISAM;

Réalisation de votre bot PHP

Je vous rappelle que ce tutoriel n'est en aucun cas là pour vous fournir une solution clefs en mains. Nous allons juste vous donner les outils nécessaires à la fabrication de votre robot.

Le script va comporter deux parties : une qui indexera automatiquement tous les fichiers de votre site web et leur hash MD5, tandis que l'autre comparera les hash MD5.

L'indexation



Indexer tous les path des fichiers à surveiller ainsi que leur hash MD5 est une opération longue et fastidieuse si vous la réalisez manuellement.
Nous allons ici automatiser cette indexation à l'aide d'une fonction reposant sur les fonctions opendir et readdir de PHP.

Cette fonction récursive va lister tous les répertoires qu'elle va trouver, calculer le hash MD5 de chaque fichier et les ajouter dans la base de données.

Voici la fonction en question :

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
function liste_file_hash($dir)
{
    // On ouvre le dossier
    if ($dossier = opendir($dir)) {
        // On recherche tous les dossiers et fichiers qu'il contient
        while ($fichier = readdir($dossier)) {
            // Le path du dossier actuel
            $path = $dir . '/' . $fichier;

            // Si on rencontre un dossier, alors on relance la fonction pour rechercher
            // de nouveau tous les fichiers et dossiers qu'il contient
            if ($fichier != '.' && $fichier != '..' && is_dir($path))
                liste_file_hash($path);

            // Si on a affaire à un fichier
            elseif ($fichier != '.' && $fichier != '..' && !is_dir($path)) {
                echo $path . ' - hash(' . md5_file($path) . ')<br />';
                // On insère le path du fichier et son hash MD5
                mysql_query('INSERT INTO `bot_fichiers` ( `file_id` , `path` , `hash` )
                             VALUES (NULL , \'' . $path . '\', \'' . md5_file($path) . '\');') or die('Erreur : ' . mysql_error());
            }
        }
        closedir($dossier);
    }
}
?>


Le bot de vérification



Nous allons passer à la deuxième partie du bot : la vérification des fichiers et de leur hash MD5.
Le bot va procéder de la manière suivante : tout d'abord, il récupère la liste des fichiers (et leur hash) à vérifier dans la base de données.
Il compare ensuite le hash MD5 contenu dans la base de données au hash actuel. S'ils ne correspondent pas, alors un rapport est envoyé par e-mail, pour vous avertir que quelqu'un a modifié ce fichier.

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
// On récupère la liste des fichiers & leur hash
$requete = 'SELECT * FROM `bot_fichiers`';
$query = mysql_query($requete) or die('Erreur : ' . mysql_error());

$rapport = null;

while ($row = mysql_fetch_array($query)) {

    // On vérifie l'existence du fichier
    if (file_exists($row['path'])) {

        // On calcule le hash MD5 du fichier
        $hash_md5 = md5_file($row['path']);
        if ($hash_md5 == false)
            $rapport .= 'Impossible de récupérer la chaîne MD5 du fichier (' . $row['path'] . ')<br />';

        else {
            // Si le hash MD5 ne correspond pas
            if ($hash_md5 != $row['hash'])
                $rapport .= 'Le hash MD5 du fichier ' . $row['path'] . ' ne correspond pas !<br />';
        } 

    } else // Si le fichier n'existe pas
        $rapport .= 'Le fichier ' . $row['path'] . ' n\'est pas présent sur le disque<br />';
} 

// On envoie le rapport si nécessaire
if (!empty($rapport)) {
    $entetes = "Content-type: text/html; Charset=iso-8859-1\n\r" ;
    $entetes .= "From: " . EMAIL_ADMIN . "\n\r"; 
    $send = mail(EMAIL_ADMIN, '[BOT MD5] Rapport', $rapport, $entetes);
    if (!$send)
        echo '<p>Impossible d\'envoyer le mail</p>';

    echo $rapport;

} else
    echo '<p>Aucun fichier n\'a été modifié</p>';

?>

Amélioration du code source

Vous avez maintenant un script qui effectuera sans problème la tâche pour laquelle nous l'avons conçu.
Cependant, n'oubliez pas qu'il est loin d'être parfait ; je vous encourage vivement à rajouter plusieurs fonctionnalités.

Voici quelques idées



Le code complet

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?php
error_reporting(E_ALL);
set_time_limit(0);

define('EMAIL_ADMIN', 'votremail@gmail.com');
define('HOME_WWW', '/home/seb/www');
define('DBHOST', 'localhost');
define('DBUSER', 'user');
define('DBPASS', 'pass');
define('DBBASE', 'base');

// Connexion à la base de données
mysql_connect(DBHOST, DBUSER, DBPASS) or die('Erreur : ' . mysql_error());
mysql_select_db(DBBASE) or die('Erreur : ' . mysql_error());

function liste_file_hash($dir)
{
    // On ouvre le dossier
    if ($dossier = opendir($dir)) {
        // On recherche tous les dossiers et fichiers qu'il contient
        while ($fichier = readdir($dossier)) {
            // Le path du dossier actuel
            $path = $dir . '/' . $fichier;
            // Si on rencontre un dossier, alors on relance la fonction pour rechercher
            // de nouveau tous les fichiers et dossiers qu'il contient
            if ($fichier != '.' && $fichier != '..' && is_dir($path))
                liste_file_hash($path);
            // Si on a affaire à un fichier
            elseif ($fichier != '.' && $fichier != '..' && !is_dir($path)) {
                echo $path . ' - hash(' . md5_file($path) . ')<br />';
                // On insère le path du fichier et son hash MD5
                mysql_query('INSERT INTO `bot_fichiers` ( `file_id` , `path` , `hash` )
                             VALUES (NULL , \'' . $path . '\', \'' . md5_file($path) . '\');') or die('Erreur : ' . mysql_error());
            }
        }
        closedir($dossier);
    }
}

// DEUX MODES D'UTILISATION : indexation & vérification

// INDEXATION - index.php?add
if (isset($_GET['add'])) {
    liste_file_hash(HOME_WWW);

// VERIFICATION - index.php
} else {
    // On récupère la liste des fichiers & leur hash
    $requete = 'SELECT * FROM `bot_fichiers`';
    $query = mysql_query($requete) or die('Erreur : ' . mysql_error());

    $rapport = null;

    while ($row = mysql_fetch_array($query)) {
        // On vérifie l'existence du fichier
        if (file_exists($row['path'])) {
            // On calcule le hash MD5 du fichier
            $hash_md5 = md5_file($row['path']);
            if ($hash_md5 == false)
                $rapport .= 'Impossible de récupérer la chaîne MD5 du fichier (' . $row['path'] . ')<br />';

            else {
                // Si le hash MD5 ne correspond pas
                if ($hash_md5 != $row['hash'])
                    $rapport .= 'Le hash MD5 du fichier ' . $row['path'] . ' ne correspond pas !<br />';
            }
        } else // Si le fichier n'existe pas
            $rapport .= 'Le fichier ' . $row['path'] . ' n\'est pas présent sur le disque<br />';
    }
    // On envoie le rapport si nécessaire
    if (!empty($rapport)) {
        $entetes = "Content-type: text/html; Charset=iso-8859-1\n\r" ;
        $entetes .= "From: " . EMAIL_ADMIN . "\n\r";
        $send = mail(EMAIL_ADMIN, '[BOT MD5] Rapport', $rapport, $entetes);
        if (!$send)
            echo '<p>Impossible d\'envoyer le mail</p>';

        echo $rapport;
    } else
        echo '<p>Aucun fichier n\'a été modifié</p>';
}

mysql_close();
?>

Quelques liens

Voici quelques liens intéressants sur PHP et la sécurité. N'ayant pas traité ce point-là dans ce tutoriel, je vous invite à aller vous documenter. :)


Voilà, vous avez maintenant tout pour réaliser votre bot. :)

Je vous conseille d'utiliser ce bot uniquement sur un site fini, pour éviter la contrainte de la mise à jour des hashes à chaque modification de l'un de vos fichiers !

Amusez-vous bien ! ^^
Image utilisateur
Auteur : Seb-D
Noter et commenter ce tutoriel
Imprimer ce tutoriel

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | Fil RSS | XHTML 1.0 | CSS 2.0
Édité par Simple IT SARL : Nous contacter | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !

Hébergement web - Correction de tutoriels - Créer un site
Vous souhaitez apparaître ici ? Contactez-nous.

Nombre de connectés 577 Zéros connectés | Requêtes SQL 7 requêtes | Temps de génération de la page : Total (SQL) 0.0253s (0.0075s)