PHP-IDS, ou comment protéger son site web

Il y a quelques temps, j’ai découvert un outil indispensable, et qui plus est open source… Il n’en faut pas plus pour que je m’y jette dessus à corps perdus.



PHP-IDS, qu’est-ce que c’est?
Il s’agit d’un système de détection d’intrusion en php. Il s’interpose entre les pages du site, et les données entrées par l’utilisateur, et détecte les tentatives d’injection, que ce soit SQL, XSS ou autres. Utilisant un système de “points”, il va donner un poids a chaque détection, et si le total dépasse la norme tolérée, il interdit la poursuite de l’affichage de la page du site.

Attention, il ne s’agit pas pour autant d’une solution miracle! Il reste nécessaire de bien coder afin d’éviter des problèmes. Mais il fournit une protection suplémentaire au site sur lequel il est configuré.

Mise en place

  1. On récupère les sources sur le site officiel : http://php-ids.org/downloads/
  2. On décompresse nos sources
  3. On mets à jour les fichiers default_filter.xml et converter.php afin d’avoir des données le plus a jour possible
    https://svn.php-ids.org/svn/trunk/lib/IDS/default_filter.xml
    https://svn.php-ids.org/svn/trunk/lib/IDS/Converter.php
  4. On place le répertoire lib/IDS dans les librairies de notre projet
  5. On configure le fichier IDS/Config/Config.ini
    ; PHPIDS Config.ini
    
    ; General configuration settings
    
    ; !!!DO NOT PLACE THIS FILE INSIDE THE WEB-ROOT
    ; IF DATABASE CONNECTION DATA WAS ADDED!!!
    
    [General]
    
        ; basic settings - customize to make the PHPIDS work at all
        filter_type     = xml
        filter_path     = /chemin/vers/lib/IDS/default_filter.xml
        tmp_path        = /chemin/vers/lib/IDS/tmp
        scan_keys       = false
    
        ; in case you want to use a different HTMLPurifier source, specify it here
        ; By default, those files are used that are being shipped with PHPIDS
        HTML_Purifier_Path  = IDS/vendors/htmlpurifier/HTMLPurifier.auto.php
        HTML_Purifier_Cache = IDS/vendors/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer
    
        ; define which fields contain html and need preparation before
        ; hitting the PHPIDS rules (new in PHPIDS 0.5)
        html[]          = __wysiwyg
    
        ; define which fields shouldn't be monitored (a[b]=c should be referenced via a.b)
        exceptions[]    = __utmz
        exceptions[]    = __utmc
    
        ; PHPIDS should run with PHP 5.1.2 but this is untested - set
        ; this value to force compatibilty with minor versions
        ;min_php_version = 5.1.6
        min_php_version = 5.1.2
    
    ; If you use the PHPIDS logger you can define specific configuration here
    
    [Logging]
    
        ; file logging
        ; non necessaire si log via DB
        path            = /chemin/vers/lib/IDS/tmp/phpids_log.txt
    
        ; email logging
    
        ; note that enabling safemode you can prevent spam attempts,
        ; see documentation
        recipients[]    = test@test.com.invalid
        subject         = "PHPIDS detected an intrusion attempt!"
        header          = "From: <PHPIDS> info@php-ids.org"
        safemode        = true
        allowed_rate    = 15
    
        ; database logging
    
        wrapper         = "mysql:host=localhost;port=3306;dbname=phpids"
        user            = phpids_user
        password        = phpids
        table           = intrusions
    
    ; If you would like to use other methods than file caching you can configure them here
    
    [Caching]
    
        ; caching:      session|file|database|memcached|none
        caching         = memcached
        expiration_time = 600
    
        ; file cache
        path            = /chemin/vers/lib/IDS/tmp/default_filter.cache
    
        ; database cache
        wrapper         = "mysql:host=localhost;port=3306;dbname=phpids"
        user            = phpids_user
        password        = 123456
        table           = cache
    
        ; memcached
        host           = localhost
        port           = 11211
        key_prefix     = PHPIDS
        tmp_path       = /chemin/vers/lib/IDS/tmp/memcache.timestamp
  6. La base de donnée n’est nécessaire que si l’on désire stocker les logs dedans. On peut en effet choisir si on désire un simple fichier de log, syslog, base de donnée, ou rien. Si vous désirez utiliser une base de donnée, il est nécessaire de créer la base seon les infos fournies dans le fichier de conf. POur la création de la table:
    CREATE TABLE `intrusions` (
      `id` int(11) unsigned NOT NULL auto_increment,
      `name` varchar(128) NOT NULL,
      `value` text NOT NULL,
      `page` varchar(255) NOT NULL,
      `userid` int(11) unsigned NOT NULL,
      `session` varchar(32) NOT NULL,
      `ip` varchar(15) NOT NULL,
      `reaction` tinyint(3) unsigned NOT NULL COMMENT '0 = log; 1 = mail; 2 = warn; 3 = kick;',
      `impact` int(11) unsigned NOT NULL,
      `created` datetime NOT NULL,
      PRIMARY KEY  (`id`)
    );
  7. Une fois configurer, il ne reste plus qu’a l’inclure dans nos sites. Pour cela, je vous conseille de créer un fichier prepend, et de configurer le htaccess pour le charger en priorité. Voici un exemple du fichier de traitement. A vous de l’adapter selon vos besoins:
    <?php
    
    // On rajoute le chemin de la lib
    set_include_path(
        get_include_path()
        . PATH_SEPARATOR
        . '/chemin/vers/lib/'
    );
    
    // Inclusion de PHP-IDS
    require_once 'IDS/Init.php';
    
    /*
     * Un exemple d'utilisation consiste à utiliser try()
     * afin de récupérer d'éventuelles erreurs
     */
    try {
        // Attention à l'ordre des variables EGPCS
        $request = array_merge_recursive($_GET, $_POST, $_COOKIE);
        $init = IDS_Init::init(APPLI_ROOT.'/lib/IDS/Config/Config.ini');
    
        // lancement de l'IDS
        $ids = new IDS_Monitor($request, $init);
        $result = $ids->run();
    
        // Decision...
        if (!$result->isEmpty()) {
            /*
             * Pour le DEBUG il suffit de faire
             * echo $result;
             */
            // Exemple d'interpration : on affiche un msg d'erreur
            echo "Sorry, but it seems your browser has sent incorrect data.<br>";
    
            // On loggue l'attaque
            /*
             * Dans le cas d'un fichier de log :
             * require_once 'IDS/Log/File.php';
             */
            require_once 'IDS/Log/Database.php';
            require_once 'IDS/Log/Composite.php';
    
            $compositeLog = new IDS_Log_Composite();
            $compositeLog->addLogger(IDS_Log_Database::getInstance($init));
            /*
             * Dans le cas d'un fichier de log
             * $compositeLog->addLogger(IDS_Log_File::getInstance($init));
             */
    
            $compositeLog->execute($result);
            die();
        } else {
            // On peut afficher quelque chose pour dire que PHPIDS tourne
            //echo '<a href="?test=%22><script>eval(window.name)</script>">No attack detected - click for an example attack</a>';
            echo "PHPIDS is running";
        }
    } catch (Exception $e) {
        printf(
            'An error occured: %s',
            $e->getMessage()
        );
    }
  8. Il ne reste plus qu’a tester l’application! Vous pouvez avoir un exemple de ce qui doit se passer ici: http://demo.php-ids.org/

Remarque: PPH-IDS nécessite au minimum PHP 5.1.2 pour fonctionner. De plus, si vous désirez logguer les données dans une base mysql, vous devrez avoir activer PDO et PDO Mysql

Posted on February 17, 2009 at 12:25 by Onet · Permalink
In: Informatique, Php, Programmation, Tutoriaux, Web securité · Tagged with: , , , , ,

3 Responses

Subscribe to comments via RSS

  1. Written by Khéops
    on May 22, 2009 at 22:12
    Permalink

    Dans le dernier fichier <?php n’est pas fermé ;O)

  2. Written by Onet
    on May 23, 2009 at 10:18
    Permalink

    Hello,

    C’est normal ;) En PHP, tu n’est pas obligé de fermé la balise < ?php. C'est meme fortement conseillé de ne pas le faire, cela te permets d'éviter d'avoir des suprises lors des includes avec des sessions, dans le cas ou tu aurais un retour a la ligne après.

    Php considère la fermeture de la balise lors de la fermeture du fichier si il n'y a pas de ?> ;)
    Olivier

  3. Written by MarcJ
    on May 12, 2010 at 16:30
    Permalink

    Merci beaucoup pour ce tuto.
    Juste une chose: comment configurer htaccess pour charger en priorité le fichier prepend SVP ?

Subscribe to comments via RSS

Leave a Reply