60 votes

Comment puis-je gaz de l'utilisateur de tentatives de connexion en PHP

Je viens de lire ce post, The definitive guide pour le formulaire basé sur l'authentification de sites internet sur la Prévention Rapide-le-Feu de Tentatives de Connexion.

Meilleure pratique n ° 1: Un court laps de temps de retard qui augmente avec le nombre de tentatives qui ont échoué, comme:

1 échec de la tentative = aucun retard
2 tentatives infructueuses = 2 sec de retard
3 tentatives infructueuses = 4 sec de retard
4 tentatives infructueuses = 8 sec de retard
5 tentatives infructueuses = 16 sec de retard
etc.

DoS attaquer ce régime serait très peu pratique, mais d'un autre côté, potentiellement dévastatrice, car le retard augmente de façon exponentielle.

Je suis curieux de savoir comment je pourrais mettre en place quelque chose comme cela pour mon système de connexion en PHP?

84voto

cballou Points 13804

Vous ne pouvez pas simplement empêcher les attaques par déni de service par le chaînage de la limitation vers le bas à une seule adresse IP ou le nom d'utilisateur. Enfer, vous ne pouvez même pas vraiment prévenir rapide-le-feu de tentatives de connexion à l'aide de cette méthode.

Pourquoi? Parce que l'attaque peut s'étendre sur plusieurs adresses ip et des comptes d'utilisateur pour le bien de contourner la limitation de tentatives.

J'ai vu posté ailleurs que, idéalement, vous devriez être suivi de tous les échecs de tentatives de connexion sur le site et de les associer à un timestamp, peut-être:

CREATE TABLE failed_logins (
    id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(16) NOT NULL,
    ip_address INT(11) UNSIGNED NOT NULL,
    attempted DATETIME NOT NULL,
    INDEX `attempted_idx` (`attempted`)
) engine=InnoDB charset=UTF8;

Une note rapide sur l'adresse_ip champ: Vous pouvez stocker les données et récupérer les données, respectivement, avec INET_ATON() et INET_NTOA() qui correspondent à la conversion d'une adresse ip et d'un entier non signé.

# example of insertion
INSERT INTO failed_logins SET username = 'example', ip_address = INET_ATON('192.168.0.1'), attempted = CURRENT_TIMESTAMP;
# example of selection
SELECT id, username, INET_NTOA(ip_address) AS ip_address, attempted;

Décider sur un certain délai seuils sur la base de l' ensemble nombre de connexions échouées dans un laps de temps donné (15 minutes dans cet exemple). Vous devez vous baser sur des données statistiques tirées de votre failed_logins tableau qu'il va changer au fil du temps basé sur le nombre d'utilisateurs et combien d'entre eux peut rappeler (et le type) de leur mot de passe.


> 10 failed attempts = 1 second
> 20 failed attempts = 2 seconds
> 30 failed attempts = reCaptcha

Requête de la table de chaque tentative de connexion a échoué à trouver le nombre de connexions échouées sur une période de temps, disons 15 minutes:


SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute);

Si le nombre de tentatives au cours de la période de temps donnée est au-dessus de votre limite, soit de faire appliquer la limitation ou la force de l'utilisateur à utiliser un captcha (c'est à dire reCaptcha) jusqu'à ce que le nombre de tentatives infructueuses au cours de la période de temps donnée est inférieure à la valeur seuil.

// array of throttling
$throttle = array(10 => 1, 20 => 2, 30 => 'recaptcha');

// retrieve the latest failed login attempts
$sql = 'SELECT MAX(attempted) AS attempted FROM failed_logins';
$result = mysql_query($sql);
if (mysql_affected_rows($result) > 0) {
    $row = mysql_fetch_assoc($result);

    $latest_attempt = (int) date('U', strtotime($row['attempted']));

    // get the number of failed attempts
    $sql = 'SELECT COUNT(1) AS failed FROM failed_logins WHERE attempted > DATE_SUB(NOW(), INTERVAL 15 minute)';
    $result = mysql_query($sql);
    if (mysql_affected_rows($result) > 0) {
        // get the returned row
        $row = mysql_fetch_assoc($result);
        $failed_attempts = (int) $row['failed'];

        // assume the number of failed attempts was stored in $failed_attempts
        krsort($throttle);
        foreach ($throttle as $attempts => $delay) {
            if ($failed_attempts > $attempts) {
                // we need to throttle based on delay
                if (is_numeric($delay)) {
                    $remaining_delay = time() - $latest_attempt - $delay;
                    // output remaining delay
                    echo 'You must wait ' . $remaining_delay . ' seconds before your next login attempt';
                } else {
                    // code to display recaptcha on login form goes here
                }
                break;
            }
        }        
    }
}

L'utilisation d'un reCaptcha à un certain seuil permettrait de s'assurer qu'une attaque à partir de plusieurs fronts serait arrêté et normal, les utilisateurs du site ne serait pas l'expérience d'un délai important pour légitime échecs de tentatives de connexion.

6voto

Mark Elliot Points 31871

Vous disposez de trois méthodes de base: stocker les informations de session, de stocker des informations de cookie ou de stocker des informations de propriété intellectuelle.

Si vous utilisez les informations de session de l'utilisateur final (attaquant) pourrait forcé d'invoquer de nouvelles sessions, de contourner votre tactique, et puis connectez-vous à nouveau avec aucun retard. Les séances sont assez simples à mettre en œuvre, il suffit de stocker la dernière date de connexion de l'utilisateur dans une variable de session, il correspond à contre-courant du temps, et assurez-vous que le retard a été assez long.

Si vous utilisez des témoins, l'agresseur peut tout simplement refuser les cookies, dans l'ensemble, ce n'est vraiment pas quelque chose de viable.

Si vous suivez les adresses IP, vous aurez besoin de stocker des tentatives de connexion à partir d'une adresse IP en quelque sorte, de préférence dans une base de données. Lorsqu'un utilisateur tente de se connecter, il suffit de mettre à jour votre liste d'adresses ip. Vous devez purger ce tableau dans un délai raisonnable, le dumping des adresses IP qui n'ont pas été actif dans un certain temps. Le piège (il y a toujours un piège), c'est que certains utilisateurs peuvent finissent par le partage d'une adresse IP, et dans des conditions limites, vos retards peuvent affecter les utilisateurs par mégarde. Puisque vous êtes l'échec du suivi des connexions, et seulement échoué connexions, cela ne devrait pas causer trop de douleur.

4voto

Don Turnblade Points 21

Le processus d'identification des besoins de réduire sa vitesse pour tant de succès et d'échec de connexion. La tentative de connexion elle-même ne doit jamais être plus rapide que d'environ 1 seconde. Si c'est la force brute qui utilise le retard de savoir que la tentative a échoué parce que le succès est plus courte que celle de l'échec. Ensuite, plusieurs combinaisons peuvent être évalués par seconde.

Le nombre de simultanée de tentatives de connexion par machine doit être limitée par l'équilibreur de charge. Enfin, vous avez juste besoin de suivre si le même utilisateur ou le mot de passe est utilisé par plus d'un utilisateur/mot de passe tentative de connexion. Les humains ne peuvent pas taper plus vite que d'environ 200 mots par minite. Donc, successive ou simultanée, de tentatives de connexion plus rapide que 200 mots par minite sont à partir d'un ensemble de machines. Ceux-ci peuvent donc être rattachée à une liste noire en toute sécurité car il n'est pas votre client. Liste noire fois par l'hôte n'a pas besoin d'être supérieure à 1 seconde environ. Ce ne sera jamais les inconvénients de l'homme, mais fait des ravages avec une force brutale tentative de s'en série ou en parallèle.

2 * 10^19 combinaisons une combinaison par seconde, de s'exécuter en parallèle sur 4 milliards de dollars séparer les adresses IP, prendra 158 ans, afin d'échappement, comme un espace de recherche. Pour une durée d'un jour par l'utilisateur à l'encontre de 4 milliards d'attaquants, vous avez besoin d'un entièrement aléatoire de mot de passe alphanumérique 9 places de long au minimum. Envisager la formation des utilisateurs dans des phrases de passe d'au moins 13 places de long, 1.7 * 10^20 combinaisons.

Ce retard, de motiver l'attaquant de voler votre mot de passe de fichier de hachage plutôt que la force brute de votre site. L'utilisation est approuvé, nommé, techniques de hachage. L'interdiction de l'ensemble de la population de l'IP Internet pendant une seconde, permettra de limiter l'effet des attaques parallèles sans dealy un homme devrait apprécier. Enfin, si votre système le permet plus de 1000 tentatives d'ouverture de session dans une seconde sans réponse pour l'interdiction des systèmes, puis votre plan de sécurité ont plus de problèmes pour travailler sur. Correctif automatisé de réponse tout d'abord.

3voto

Tyler Carter Points 30030
session_start();
$_SESSION['hit'] += 1; // Only Increase on Failed Attempts
$delays = array(1=>0, 2=>2, 3=>4, 4=>8, 5=>16); // Array of # of Attempts => Secs

sleep($delays[$_SESSION['hit']]); // Sleep for that Duration.

ou comme suggéré par Cyro:

sleep(2 ^ (intval($_SESSION['hit']) - 1));

C'est un peu rude, mais les composants de base sont là. Si vous actualisez cette page, à chaque fois que vous actualisez le retard va s'allonger.

Vous pouvez aussi garder le compte dans une base de données, où vous vérifiez le nombre de tentatives infructueuses par la propriété intellectuelle. En l'utilisant, basé sur l'IP et de conserver les données de votre côté, vous empêcher l'utilisateur d'être en mesure d'effacer ses cookies pour arrêter le retard.

En gros, le début du code:

$count = get_attempts(); // Get the Number of Attempts

sleep(2 ^ (intval($count) - 1));

function get_attempts()
{
    $result = mysql_query("SELECT FROM TABLE WHERE IP=\"".$_SERVER['REMOTE_ADDR']."\"");
    if(mysql_num_rows($result) > 0)
    {
        $array = mysql_fetch_assoc($array);
        return $array['Hits'];
    }
    else
    {
        return 0;
    }
}

3voto

Matchu Points 37755

Magasin échouer les tentatives dans la base de données par la propriété intellectuelle. (Puisque vous avez un système de connexion, je suppose que vous savez très bien comment faire cela.)

Évidemment, les sessions est tentant de méthode, mais quelqu'un de vraiment dédié peuvent assez facilement se rendre compte qu'ils peuvent tout simplement supprimer son cookie de session sur l'échec des tentatives visant à contourner la manette des gaz entièrement.

Sur la tentative de connexion, chercher combien récente (disons, les 15 dernières minutes) de tentatives de connexion, il y avait, et l'heure de la dernière tentative.

$failed_attempts = 3; // for example
$latest_attempt = 1263874972; // again, for example
$delay_in_seconds = pow(2, $failed_attempts); // that's 2 to the $failed_attempts power
$remaining_delay = time() - $latest_attempt - $delay_in_seconds;
if($remaining_delay > 0) {
    echo "Wait $remaining_delay more seconds, silly!";
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X