Annonce ToutSurTout

Bienvenue sur toutsurtout.biz

Déjà 15 ans !

Radio TST

Si vous souhaitez participer vous aussi aux discussions sur le forum, il faut vous inscrire ou vous identifier.

Le Thème TST Automne est maintenant en place.

Les inscriptions sont actuellement OUVERTES.

Message 1 Discussion postée le 07-08-2013 à 19:27:31

Philippe
Avatar de Philippe


Titre: Banni
Avancement: Niveau 3
Date d'inscription: 26-09-2009
Messages: 3 660

Sécurisation d'applications Web - Système de bannissement en php

J'ai ajouté mon système de bannissement d'adresse IP au système de login de Codiad. Trop d'essais avec le mauvais mot de passe, et l'adresse IP est bannie pendant 30 minutes. C'est suffisant pour bloquer les attaques de type brute-force. C'est très facile à ajouter, ça m'a pris 2 minutes, et ce genre de manipulation peut se faire sur pratiquement n'importe quelle appli web sans trop de difficultés. Il suffit de localiser l'endroit du code qui vérifie la validité du mot de passe.

Voilà comment procéder pour Codiad: J'ai mis mon petit "ban.php" dans le répertoire /component/user/ de Codiad:

<?php

date_default_timezone_set('Europe/Paris');
$GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory
$GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php'; // File storage for failures and bans.
$GLOBALS['config']['BAN_AFTER'] = 5; // Ban IP after this many failures.
$GLOBALS['config']['BAN_DURATION'] = 1800; // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes)
if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); }
if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files.

function logm($message)
{
    $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n";
    file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt',$t,FILE_APPEND);
}


// ------------------------------------------------------------------------------------------
// Brute force protection system
// Several consecutive failed logins will ban the IP address for 30 minutes.
if (!is_file($GLOBALS['config']['IPBANS_FILENAME'])) file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>");
include $GLOBALS['config']['IPBANS_FILENAME'];
// Signal a failed login. Will ban the IP if too many failures:
function ban_loginFailed()
{
    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
    if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0;
    $gb['FAILURES'][$ip]++;
    if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1))
    {
        $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION'];
        logm('IP address banned from login');
    }
    $GLOBALS['IPBANS'] = $gb;
    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
}

// Signals a successful login. Resets failed login counter.
function ban_loginOk()
{
    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
    unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
    $GLOBALS['IPBANS'] = $gb;
    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
    logm('Login ok.');
}

// Checks if the user CAN login. If 'true', the user can try to login.
function ban_canLogin()
{
    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
    if (isset($gb['BANS'][$ip]))
    {
        // User is banned. Check if the ban has expired:
        if ($gb['BANS'][$ip]<=time())
        { // Ban expired, user can try to login again.
            logm('Ban lifted.');
            unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
            file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
            return true; // Ban has expired, user can login.
        }
        return false; // User is banned.
    }
    return true; // User is not banned.
}

?>

puis j'ai modifié class.user.php. Voici le diff:

--- class.user.php.original    2013-08-07 18:28:37.000000000 +0200
+++ class.user.php    2013-08-07 18:31:38.000000000 +0200
@@ -5,6 +5,7 @@
*  as-is and without warranty under the MIT License. See
*  [root]/license.txt for more. This information must remain intact.
*/
+require_once 'ban.php';

class User {

@@ -54,9 +55,10 @@
                 if($user['project']!=''){ $_SESSION['project'] = $user['project']; }
             }
         }
-
-        if($pass){ echo formatJSEND("success",array("username"=>$this->username)); }
-        else{ echo formatJSEND("error","Incorrect Username or Password"); }
+       
+        if (!ban_canLogin()) { $pass=false; }
+        if($pass){ ban_loginOk(); echo formatJSEND("success",array("username"=>$this->username)); }
+        else{ ban_loginFailed(); echo formatJSEND("error","Incorrect Username or Password"); }
     }

Vous voyez, il n'y a vraiment pas grand chose à changer: 2 lignes à ajouter, et 2 lignes à modifier, et voilà un formulaire de login protégé contre le brute-force.  :-)

La petite subtilité ici, sur la manière dont je l'ai intégré, c'est que le pirate ne pourra pas faire la différence entre un bannissement et un mot de passe incorrecte: S'il est banni, on continuera à lui répondre que le mot de passe est incorrecte, même s'il est bon. Gniark gniark.


https://www.world-lolo.com/images/uploads/image.num1445754529.of.world-lolo.com.jpg
Des stades aux entrées payantes sont pleins de gens qui pensent que ceux qu'ils applaudissent sont trop payés, et les bibliothèques à l'entrée gratuite sont vides des gens qui pensent que les livres sont trop chers ...