"Rester Connecté" - la meilleure approche

mon application web utilise des sessions pour stocker des informations sur l'utilisateur une fois qu'ils se sont connectés, et pour maintenir cette information pendant qu'ils voyagent d'une page à l'autre dans l'application. Dans cette application spécifique, je stocke les user_id , first_name et last_name de la personne.

j'aimerais offrir une option "Keep Me Logged In" sur log in qui mettra un cookie sur la machine de l'utilisateur pendant deux semaines, qui reprendra leur session avec les mêmes détails quand ils retournent à l'application.

Quelle est la meilleure approche pour ce faire? Je ne veux pas stocker leur user_id dans le cookie, car il semble que cela rendrait facile pour un utilisateur d'essayer de forger l'identité d'un autre utilisateur.

220
demandé sur Jimbo 2009-08-31 01:50:01

12 réponses

OK, permettez-moi de le dire sans détour: si vous mettez des données utilisateur, ou quelque chose dérivé des données utilisateur dans un cookie à cette fin, vous faites quelque chose de mal.

là. Je l'ai dit. Maintenant, nous pouvons passer à la réponse exacte.

Qu'est-ce qui ne va pas avec le hachage des données de l'utilisateur, vous demandez? Ça se résume à une surface exposée et à la sécurité par l'obscurité.

Imaginez une seconde que vous êtes un attaquant. Vous voyez un ensemble de cookies cryptographiques pour le remember-me sur votre session. Ça fait 32 caractères de large. Gee. C'est peut-être un MD5...

imaginons aussi une seconde qu'ils connaissent l'algorithme que vous avez utilisé. Par exemple:

md5(salt+username+ip+salt)

maintenant, tout ce qu'un attaquant a besoin de faire est de forcer brutalement le "sel" (qui n'est pas vraiment un sel, mais plus sur cela plus tard), et il peut maintenant générer tous les faux jetons qu'il veut avec n'importe quel nom d'utilisateur pour son adresse IP! Mais la brute-forçant un le sel est dur, non? Absolument. Mais les GPU modernes sont extrêmement bons à cela. Et à moins que vous n'utilisiez suffisamment d'aléatoire (faites-le assez grand), il va tomber rapidement, et avec lui les clés de votre château.

en bref, la seule chose qui vous protège est le sel, qui ne vous protège pas vraiment autant que vous le pensez.

Mais Attendez!

tout cela était prédit que l'attaquant sait l'algorithme! Si c'est secret et confus, alors tu es en sécurité, non? WRONG . Cette ligne de pensée a un nom: sécurité par L'obscurité , qui devrait jamais être invoqué.

La Meilleure Façon

la meilleure façon est de ne jamais laisser les informations d'un utilisateur quitter le serveur, sauf pour l'id.

Lorsque l'utilisateur les journaux, la création d'un grand (128 à 256 bits) aléatoire jeton. Ajoutez cela à une table de base de données qui établit la correspondance entre le token et l'identifiant utilisateur, puis envoyez-le au client dans le cookie.

et si l'attaquant devine le jeton aléatoire d'un autre utilisateur?

Eh bien, faisons quelques calculs ici. Nous générons un jeton de 128 bits. Cela signifie qu'il y a:

possibilities = 2^128
possibilities = 3.4 * 10^38

maintenant, pour montrer à quel point ce nombre est absurde, imaginons chaque serveur sur l'internet (disons 50.000.000 aujourd'hui) essayant de forcer ce nombre à un taux de 1.000.000.000 par seconde chacun. En réalité, vos serveurs fondraient sous une telle charge, mais jouons le jeu.

guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000

donc 50 milliards de conjectures par seconde. C'est rapide! Droit?

time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000

donc 6,8 sextillons secondes...

essayons de ramener cela à des nombres plus amicaux.

215,626,585,489,599 years

ou même mieux:

47917 times the age of the universe

Oui, c'est 47917 fois l'âge de l'univers...

en gros, il ne va pas être fissuré.

En résumé:

la meilleure approche que je recommande est de stocker le cookie avec trois parties.

function onLogin($user) {
    $token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
    storeTokenForUser($user, $token);
    $cookie = $user . ':' . $token;
    $mac = hash_hmac('sha256', $cookie, SECRET_KEY);
    $cookie .= ':' . $mac;
    setcookie('rememberme', $cookie);
}

puis, pour valider:

function rememberMe() {
    $cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
    if ($cookie) {
        list ($user, $token, $mac) = explode(':', $cookie);
        if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
            return false;
        }
        $usertoken = fetchTokenByUserName($user);
        if (hash_equals($usertoken, $token)) {
            logUserIn($user);
        }
    }
}

Note: N'utilisez pas le jeton ou combinaison d'utilisateur et un jeton pour rechercher un enregistrement dans votre base de données. Assurez-vous toujours de récupérer un enregistrement basé sur l'utilisateur et d'utiliser une fonction de comparaison sûre pour comparer ensuite le token récupéré. en savoir plus sur les attaques de synchronisation .

maintenant, c'est très important que le SECRET_KEY soit un secret cryptographique (généré par quelque chose comme /dev/urandom et/ou dérivé d'une entrée de haute entropie). Aussi, GenerateRandomToken() doit être une source aléatoire forte ( mt_rand() n'est pas assez fort. Utilisez une bibliothèque, telle que RandomLib ou random_compat , ou mcrypt_create_iv() avec DEV_URANDOM )...

Le hash_equals() est à éviter timing des attaques . Si vous utilisez une version PHP inférieure à PHP 5.6, la fonction hash_equals() n'est pas prise en charge. Dans ce cas, vous pouvez remplacer hash_equals() par la fonction timingSafeCompare:

/**
 * A timing safe equals comparison
 *
 * To prevent leaking length information, it is important
 * that user input is always used as the second parameter.
 *
 * @param string $safe The internal (safe) value to be checked
 * @param string $user The user submitted (unsafe) value
 *
 * @return boolean True if the two strings are identical.
 */
function timingSafeCompare($safe, $user) {
    if (function_exists('hash_equals')) {
        return hash_equals($safe, $user); // PHP 5.6
    }
    // Prevent issues if string length is 0
    $safe .= chr(0);
    $user .= chr(0);

    // mbstring.func_overload can make strlen() return invalid numbers
    // when operating on raw binary strings; force an 8bit charset here:
    if (function_exists('mb_strlen')) {
        $safeLen = mb_strlen($safe, '8bit');
        $userLen = mb_strlen($user, '8bit');
    } else {
        $safeLen = strlen($safe);
        $userLen = strlen($user);
    }

    // Set the result to the difference between the lengths
    $result = $safeLen - $userLen;

    // Note that we ALWAYS iterate over the user-supplied length
    // This is to prevent leaking length information
    for ($i = 0; $i < $userLen; $i++) {
        // Using % here is a trick to prevent notices
        // It's safe, since if the lengths are different
        // $result is already non-0
        $result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
    }

    // They are only identical strings if $result is exactly 0...
    return $result === 0;
}
627
répondu ircmaxell 2016-04-27 08:48:43

Avis de Sécurité : Fonder le témoin off un hachage MD5 de déterministe de données est une mauvaise idée; il est préférable d'utiliser un jeton aléatoire dérivé d'un CSPRNG. Voir la réponse de ircmaxell à cette question pour une approche plus sûre.

Habituellement, je fais quelque chose comme ça:

  1. Utilisateur se connecte avec "rester connecté"
  2. créer session
  3. créer un cookie appelé SOMETHING called SOMETHING containing: md5 (salt+username+ip+salt) et un cookie appelé somethingElse containing id
  4. Magasin de cookies dans la base de données
  5. Utilisateur n'trucs et feuilles ----
  6. Les retours D'Utilisateur, vérifier pour un cookie somethingElse, s'il existe, obtenir le vieux hash de la base de données pour cet utilisateur, Vérifier le contenu de cookie quelque chose de match avec le hash de la base de données, qui devrait également correspondre à un hash nouvellement calculé (pour la ip) ainsi: cookieHash= = databaseHash= = md5 (sel+nom d'Utilisateur+ip+sel), si elles le font, passez à 2, si elles ne vont pas à 1

bien sûr, vous pouvez utiliser différents noms de cookies, etc. vous pouvez également modifier le contenu du cookie un peu, assurez-vous qu'il n'est pas facilement créés. Vous pouvez par exemple créer un user_salt lorsque l'utilisateur est créé et aussi mettre que dans le témoin.

vous pouvez Également utiliser sha1 au lieu de md5 (ou à peu près n'importe quel algorithme)

94
répondu Pim Jager 2017-05-23 12:26:32

Introduction

Votre titre "rester Connecté" - la meilleure approche il est difficile pour moi de savoir par où commencer, parce que si vous êtes à la recherche à la meilleure approche alors que vous auriez à compte de ce qui suit :

  • Identification
  • Sécurité

Cookies

les Cookies sont vulnérables, entre les vulnérabilités courantes de vol de cookies de navigateur et les attaques de scripts de site nous devons accepter que les cookies ne sont pas sûrs. Pour aider à améliorer la sécurité, vous devez noter que php setcookies a des fonctionnalités supplémentaires telles que

bool setcookie (chaîne $name [, chaîne $ value [, int $ expire = 0 [, chaîne $path [, chaîne $ domain [, bool $secure = false [, bool $httponly = false ]]]]]] )

  • sécurisé (à l'Aide de la connexion HTTPS)
  • httponly (Réduire le vol d'identité par le biais attaque XSS)

définitions

  • Token (chaîne aléatoire imprévisible de n Longueur eg. / dev / urandom)
  • référence (chaîne aléatoire imprévisible de n longueur par exemple. / dev / urandom)
  • Signature (Générer un hachage à clé de la valeur à l'aide de l'algorithme HMAC méthode)

Approche Simple

une solution simple serait:

  • L'utilisateur est connecté avec Remember Me""
  • Cookie de connexion émis avec token & Signature
  • Quand est de retour , la Signature est vérifiée
  • si la Signature est ok .. puis nom d'utilisateur & jeton est recherché dans la base de données
  • si non valide .. retour à la page de connexion
  • Si valide automatiquement de connexion

l'étude de cas ci-dessus résume tous les exemples donnés sur cette page mais ils inconvénients est que

  • il n'y a aucun moyen de savoir si les cookies ont été volés
  • L'attaquant
  • peut avoir accès opérations sensibles telles que le changement de mot de passe ou des données telles que des informations personnelles et de cuisson, etc.
  • Le compromis cookie reste valide pour le cookie durée de vie

Meilleure Solution

une meilleure solution serait

  • L'utilisateur est connecté et se souvenir de moi est sélectionné
  • générer jeton & signature et stocker dans cookie
  • les jetons sont aléatoires et ne sont valables que pour une seule authentification
  • les jetons sont remplacés à chaque visite sur le site
  • Lorsqu'un utilisateur non connecté visite le site , la signature, le jeton et le nom d'utilisateur sont vérifiés
  • rappelez-vous que le login me devrait avoir un accès limité et ne pas permettre la modification du mot de passe , des renseignements personnels, etc.

exemple Code

// Set privateKey
// This should be saved securely 
$key = 'fc4d57ed55a78de1a7b31e711866ef5a2848442349f52cd470008f6d30d47282';
$key = pack("H*", $key); // They key is used in binary form

// Am Using Memecahe as Sample Database
$db = new Memcache();
$db->addserver("127.0.0.1");

try {
    // Start Remember Me
    $rememberMe = new RememberMe($key);
    $rememberMe->setDB($db); // set example database

    // Check if remember me is present
    if ($data = $rememberMe->auth()) {
        printf("Returning User %s\n", $data['user']);

        // Limit Acces Level
        // Disable Change of password and private information etc

    } else {
        // Sample user
        $user = "baba";

        // Do normal login
        $rememberMe->remember($user);
        printf("New Account %s\n", $user);
    }
} catch (Exception $e) {
    printf("#Error  %s\n", $e->getMessage());
}

Classe Utilisée

class RememberMe {
    private $key = null;
    private $db;

    function __construct($privatekey) {
        $this->key = $privatekey;
    }

    public function setDB($db) {
        $this->db = $db;
    }

    public function auth() {

        // Check if remeber me cookie is present
        if (! isset($_COOKIE["auto"]) || empty($_COOKIE["auto"])) {
            return false;
        }

        // Decode cookie value
        if (! $cookie = @json_decode($_COOKIE["auto"], true)) {
            return false;
        }

        // Check all parameters
        if (! (isset($cookie['user']) || isset($cookie['token']) || isset($cookie['signature']))) {
            return false;
        }

        $var = $cookie['user'] . $cookie['token'];

        // Check Signature
        if (! $this->verify($var, $cookie['signature'])) {
            throw new Exception("Cokies has been tampared with");
        }

        // Check Database
        $info = $this->db->get($cookie['user']);
        if (! $info) {
            return false; // User must have deleted accout
        }

        // Check User Data
        if (! $info = json_decode($info, true)) {
            throw new Exception("User Data corrupted");
        }

        // Verify Token
        if ($info['token'] !== $cookie['token']) {
            throw new Exception("System Hijacked or User use another browser");
        }

        /**
         * Important
         * To make sure the cookie is always change
         * reset the Token information
         */

        $this->remember($info['user']);
        return $info;
    }

    public function remember($user) {
        $cookie = [
                "user" => $user,
                "token" => $this->getRand(64),
                "signature" => null
        ];
        $cookie['signature'] = $this->hash($cookie['user'] . $cookie['token']);
        $encoded = json_encode($cookie);

        // Add User to database
        $this->db->set($user, $encoded);

        /**
         * Set Cookies
         * In production enviroment Use
         * setcookie("auto", $encoded, time() + $expiration, "/~root/",
         * "example.com", 1, 1);
         */
        setcookie("auto", $encoded); // Sample
    }

    public function verify($data, $hash) {
        $rand = substr($hash, 0, 4);
        return $this->hash($data, $rand) === $hash;
    }

    private function hash($value, $rand = null) {
        $rand = $rand === null ? $this->getRand(4) : $rand;
        return $rand . bin2hex(hash_hmac('sha256', $value . $rand, $this->key, true));
    }

    private function getRand($length) {
        switch (true) {
            case function_exists("mcrypt_create_iv") :
                $r = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
                break;
            case function_exists("openssl_random_pseudo_bytes") :
                $r = openssl_random_pseudo_bytes($length);
                break;
            case is_readable('/dev/urandom') : // deceze
                $r = file_get_contents('/dev/urandom', false, null, 0, $length);
                break;
            default :
                $i = 0;
                $r = "";
                while($i ++ < $length) {
                    $r .= chr(mt_rand(0, 255));
                }
                break;
        }
        return substr(bin2hex($r), 0, $length);
    }
}

les Tests dans Firefox & Chrome

enter image description here

avantage

  • Meilleure Sécurité
  • accès limité pour attaquant
  • lorsque cookie est volé ses seulement valide pour un accès
  • lorsque l'utilisateur d'origine accède au site, vous pouvez automatiquement détecter et notifier l'utilisateur de vol

désavantage

  • ne supporte pas la connexion persistante via plusieurs navigateurs (Mobile et Web)
  • le cookie peut encore être volé car l'utilisateur ne reçoit la notification qu'après la prochaine connexion.

Quick Fix

  • Introduction d'un système d'homologation pour chaque système qui doit avoir une connexion persistante
  • utiliser plusieurs cookies pour l'authentification

Plusieurs Cookie Approche

quand un attaquant est sur le point de voler cookes le seul focus il sur un site web particulier ou domaine par exemple. example.com

mais vraiment vous pouvez authentifier un utilisateur à partir de 2 domaines différents ( example.com & fakeaddsite.com ) et le faire ressembler à "Cookie publicitaire"

  • L'utilisateur S'est connecté à example.com with remember me
  • stocker nom d'utilisateur, token, référence dans le cookie
  • magasin nom d'utilisateur , un jeton de référence dans la Base de données par exemple. Memcache
  • Envoyer refrence id via get et de l'iframe de fakeaddsite.com
  • fakeaddsite.com utilise la référence pour récupérer l'utilisateur et le token de la base de données
  • fakeaddsite.com conserve la signature
  • Lorsqu'un utilisateur retourne des informations de signature fetch avec iframe fakeaddsite.com
  • combiner les données et faire le validation
  • ..... vous connaissez le reste

certains pourraient se demander comment vous pouvez utiliser 2 cookies différents ? Eh bien son possible, imaginez example.com = localhost et fakeaddsite.com = 192.168.1.120 . Si vous inspectez les cookies, il ressemblerait à ceci

enter image description here

de l'image ci-dessus

  • le site actuellement visité est localhost
  • il contient aussi des cookies de 192.168.1.120

192.168.1.120

  • accepte seulement défini HTTP_REFERER
  • n'accepte que la connexion spécifiée REMOTE_ADDR
  • Pas de JavaScript , Pas de contenu, mais comprennent rien plutôt que de signer l'information et de l'ajouter ou de le récupérer à partir de cookie

avantage

  • 99% pourcentage du temps où vous avez trompé l'attaquant
  • vous pouvez facilement verrouiller le compte dans la première tentative de l'attaquant
  • L'attaque peut être évitée même avant la prochaine connexion comme les autres méthodes

désavantage

  • Plusieurs Demande au serveur juste pour un seul login

amélioration

  • fait usage iframe use ajax
67
répondu Baba 2013-07-12 12:49:03

il y a deux articles très intéressants, j'ai trouvé tout en recherchant une solution parfaite pour le"remember-me" problème:

24
répondu Stefan Gehrig 2009-08-31 06:38:23

j'ai posé un angle de cette question ici , et les réponses vous mèneront à tous les liens de cookie de temporisation-out de token-based dont vous avez besoin.

en gros, vous ne stockez pas l'identifiant de l'utilisateur dans le cookie. Vous stockez un token unique (chaîne énorme) que l'utilisateur utilise pour récupérer son ancienne session de connexion. Ensuite, pour le rendre vraiment sûr, vous demandez un mot de passe pour les opérations lourdes (comme changer le mot de passe lui-même).

6
répondu Dan Rosenstark 2017-05-23 12:10:33

je recommande L'approche mentionnée par Stefan (i.e. suivre les lignes directrices dans meilleure pratique de Cookie de connexion persistante ) et aussi recommander que vous vous assurez que vos cookies sont cookies HttpOnly de sorte qu'ils ne sont pas accessibles, potentiellement malveillants, JavaScript.

5
répondu Walter Rumsby 2010-02-20 22:40:25

générez un hash, peut-être avec un secret que vous seul connaissez, puis stockez-le dans votre DB afin qu'il puisse être associé à l'utilisateur. Devrait fonctionner assez bien.

4
répondu Jani Hartikainen 2009-08-30 21:52:54

vieux fil, mais toujours une préoccupation valable. J'ai remarqué quelques bonnes réponses à propos de la sécurité, et en évitant l'utilisation de la "sécurité par l'obscurité", mais les méthodes techniques réelles données n'étaient pas suffisantes à mes yeux. Choses que je dois dire avant de contribuer ma méthode:

  • jamais conservez un mot de passe dans un texte clair...JAMAIS!
  • NEVER stocker le mot de passe d'un utilisateur dans plus d'un endroit en votre base de données. Votre serveur d'arrière-plan est toujours capable de tirer le mot de passe hashé de la table des utilisateurs. Il n'est pas plus efficace de stocker des données redondantes au lieu de transactions DB supplémentaires, l'inverse est vrai.
  • vos ID de Session devraient être uniques, de sorte qu'Aucun utilisateur ne pourrait jamais partager un ID, d'où l'objet D'un ID (votre numéro D'ID de permis de conduire pourrait-il jamais correspondre à une autre personne? Aucun.) Cela génère une combinaison unique de deux pièces, basée sur 2 chaînes uniques. Votre table de Sessions devrait utiliser L'ID comme PK. Pour permettre de faire confiance à plusieurs dispositifs pour auto-signer, utilisez une autre table pour les dispositifs de confiance qui contient la liste de tous les dispositifs validés (voir mon exemple ci-dessous), et est mappé en utilisant le nom d'utilisateur.
  • il ne sert à rien de masquer des données connues dans un cookie, le cookie peut être copié. Ce que nous recherchons est un dispositif utilisateur conforme de fournir des informations authentiques qui ne peuvent pas être obtenus sans un attaquant compromettant la machine de l'utilisateur (encore une fois, Voir mon exemple). Cela signifierait, cependant, qu'un utilisateur légitime qui interdit les informations statiques de sa machine (c.-à-d. adresse MAC, nom d'hôte du périphérique, utilisateur s'il est limité par le navigateur, etc.) de rester cohérent (ou des parodies en premier lieu) ne sera pas en mesure d'utiliser cette fonctionnalité. Mais si cela est un problème, considérez le fait que vous offrez auto-signin aux utilisateurs qui s'identifient de façon unique , donc s'ils refusent d'être connus par mystification de leur MAC, mystification de leur nom d'utilisateur, mystification/modification de leur nom d'hôte, se cacher derrière des procurations, etc., alors ils ne sont pas identifiables, et ne devraient jamais être authentifiés pour un service automatique. Si vous voulez cela, vous devez regarder dans la carte à puce d'accès fourni avec logiciel client qui établit l'identité de l'appareil utilisé.

que tout étant dit, Il ya deux grandes façons d'avoir Auto-signin sur votre système.

D'abord, le moyen facile et bon marché qui met tout sur quelqu'un d'autre. Si vous faites de votre site le support de connexion avec, disons, votre compte google+, vous avez probablement un bouton rationalisé de google+ qui va se connecter à l'utilisateur si ils sont déjà signés dans google (je l'ai fait ici pour répondre à cette question, comme je suis toujours signé dans google). Si vous voulez que l'utilisateur se connecte automatiquement s'ils sont déjà connectés avec un authentificateur fiable et pris en charge, et coché la boîte pour le faire, demandez à vos scripts côté client d'exécuter le code derrière le bouton 'Se connecter avec' avant le chargement, assurez-vous juste que le serveur stocke un ID unique dans une table auto-signer qui a le nom d'utilisateur, L'ID de session, et l'authentificateur utilisé pour l'utilisateur. Puisque ces méthodes de connexion utilisent AJAX, vous attendez une réponse de toute façon, et cette réponse est soit une réponse validée, soit un rejet. Si vous obtenez une réponse validée, utilisez-la comme d'habitude, puis continuez à charger le connecté en utilisateur normal. Sinon, la connexion a échoué, mais ne dites pas à l'utilisateur, il suffit de continuer comme pas connecté, ils le remarqueront. Il s'agit d'empêcher un attaquant qui a volé des cookies (ou les a contrefaits dans une tentative d'escalader les privilèges) d'apprendre que l'utilisateur auto-signe dans le site.

C'est pas cher, et pourrait également être considéré sale par certains parce qu'il essaie de valider votre potentiellement déjà signé en soi avec des endroits comme Google et Facebook, sans même il vous dit. Il ne doit toutefois pas être utilisé sur les utilisateurs qui n'ont pas demandé à s'auto-signer sur votre site, et cette méthode particulière est uniquement pour l'authentification externe, comme avec Google+ ou FB.

parce qu'un authentificateur externe a été utilisé pour dire au serveur en coulisse si un utilisateur a été validé ou non, un attaquant ne peut rien obtenir d'autre qu'un ID unique, qui est inutile en soi. Je vais développer:

  • L'utilisateur" joe " visite le site pour la première fois, L'ID de Session est placé dans le cookie 'session'.
  • L'utilisateur ' joe 'se connecte, augmente les privilèges, obtient un nouvel ID de Session et renouvelle cookie'session'.
  • L'utilisateur ' joe 'choisit de s'auto-identifier en utilisant google+, obtient un ID unique placé dans le cookie'keepmesignedin'.
  • L'utilisateur "joe" a google les garder inscrits, permettant à votre site d'auto-inscription de l'utilisateur en utilisant google dans votre backend.
  • L'attaquant tente systématiquement IDs uniques pour "keepmesignedin" (c'est un savoir public distribué à chaque utilisateur), et n'est pas signé dans un autre endroit; tente ID unique donné à "joe".
  • Le serveur
  • reçoit un ID Unique pour "joe", tire la correspondance dans DB pour un compte google+.
  • serveur envoie attaquant à la page de connexion qui exécute une demande AJAX à google de connexion.
  • Google server reçoit requête, utilise son API pour voir attaquant n'est pas connecté actuellement.
  • Google envoie la réponse qu'il n'y a pas actuellement signé dans l'utilisateur sur cette connexion.
  • page de l'attaquant reçoit la réponse, le script redirige automatiquement vers la page de connexion avec une valeur de poste encodée dans l'url.
  • La page de connexion
  • reçoit la valeur POST, envoie le cookie pour "keepmesignedin" à une valeur vide et un valide jusqu'à la date du 1-1-1970 pour dissuader une tentative automatique, provoquant le navigateur de l'attaquant de simplement supprimer le cookie.
  • L'attaquant
  • reçoit la page de connexion normale pour la première fois.

quoi qu'il arrive, même si un attaquant utilise un ID qui n'existe pas, la tentative doit échouer sur toutes les tentatives sauf lorsqu'une réponse validée est reçue.

cette méthode peut et doit être utilisée en conjonction avec votre authentificateur interne pour ceux qui se connectent à votre site en utilisant un authentificateur externe.

=========

maintenant, pour votre propre système d'authentification qui peut auto-signer les utilisateurs, c'est comme ça que je le fais:

DB a quelques tables:

TABLE users:
UID - auto increment, PK
username - varchar(255), unique, indexed, NOT NULL
password_hash - varchar(255), NOT NULL
...

notez que le nom d'utilisateur peut avoir 255 caractères. J'ai mon programme de serveur qui limite les noms d'utilisateur dans mon système à 32 caractères, mais les authentificateurs externes peuvent avoir des noms d'utilisateur avec leur @domain.tld être plus grand que ça, donc je viens de soutien à la longueur maximale d'une adresse e-mail pour une compatibilité maximale.

TABLE sessions:
session_id - varchar(?), PK
session_token - varchar(?), NOT NULL
session_data - MediumText, NOT NULL

notez qu'il n'y a pas de champ utilisateur dans ce tableau, car le nom d'utilisateur, une fois connecté, est dans les données de session, et le programme n'autorise pas les données nulles. Le session_id et le session_token peuvent être générés en utilisant des hachages md5 aléatoires, des hachages sha1/128/256, des tampons datetime avec des chaînes aléatoires ajoutées à eux puis hachés, ou tout ce que vous voulez, mais l'entropie de votre sortie devrait rester aussi élevé que tolérable pour atténuer les attaques par la force brute, même au départ, et tous les hashs générés par votre classe de session doivent être vérifiés pour les correspondances dans la table de session avant d'essayer de les ajouter.

TABLE autologin:
UID - auto increment, PK
username - varchar(255), NOT NULL, allow duplicates
hostname - varchar(255), NOT NULL, allow duplicates
mac_address - char(23), NOT NULL, unique
token - varchar(?), NOT NULL, allow duplicates
expires - datetime code
Les adresses MAC

sont par nature supposées être uniques, il est donc logique que chaque entrée ait une valeur unique. Les noms d'hôtes, d'un autre côté, pourraient être reproduits sur des réseaux séparés en toute légitimité. Combien de personnes utilisent "Home-PC" comme nom d'ordinateur? Le le nom d'utilisateur est pris à partir des données de la session par le serveur d'arrière-plan, donc la manipulation est impossible. Comme pour le token, la même méthode pour générer des tokens de session pour les pages devrait être utilisée pour générer des tokens dans les cookies pour l'utilisateur auto-signin. Enfin, le code datetime est ajouté lorsque l'Utilisateur a besoin de revalider ses informations d'identification. Soit mettre à jour cette date sur la connexion de l'utilisateur en la gardant dans quelques jours, ou la forcer à expirer indépendamment de la Dernière connexion en la gardant seulement pour un mois ou ainsi, quelle que soit votre conception de la dicte.

cela empêche quelqu'un de mystifier systématiquement le MAC et le nom d'hôte pour un utilisateur qu'ils connaissent auto-s'inscrit. JAMAIS ont à l'utilisateur de garder un cookie avec leur mot de passe en texte clair ou autrement. Faites régénérer le token sur chaque page de navigation, tout comme vous le feriez pour le token de session. Massivement réduit la probabilité qu'un attaquant pourrait obtenir un jeton valide cookie et l'utiliser pour connexion. Certaines personnes vont essayer de dire qu'un attaquant pourrait voler les cookies de la victime et faire une attaque de replay de session pour se connecter. Si un attaquant pouvait voler les cookies (ce qui est possible), ils auraient certainement compromis l'ensemble de l'appareil, ce qui signifie qu'ils pourraient simplement utiliser l'appareil pour se connecter de toute façon, ce qui va à l'encontre du but de voler les cookies entièrement. Aussi longtemps que votre site fonctionne sur HTTPS (ce qui devrait être le cas avec les mots de passe, les numéros CC ou d'autres systèmes de connexion), vous avez bénéficier de toute la protection de l'utilisateur que vous pouvez dans un navigateur.

une chose à garder à l'esprit: les données de session ne doivent pas expirer si vous utilisez auto-signin. Vous pouvez supprimer la possibilité de poursuivre la session faussement, mais la validation dans le système devrait reprendre les données de session si ce sont des données persistantes qui est prévu de continuer entre les sessions. Si vous voulez à la fois des données de session persistantes et non-persistantes, utilisez une autre table pour les données de session persistantes avec le nom d'utilisateur comme le PK, et avoir le serveur le récupèrent comme il le ferait les données de session normales, il suffit d'utiliser une autre variable.

une fois qu'une connexion a été réalisée de cette manière, le serveur doit encore valider la session. C'est là que vous pouvez coder les attentes pour les systèmes volés ou compromis; les modèles et autres résultats attendus des connexions aux données de session peuvent souvent conduire à des conclusions qu'un système a été détourné ou des cookies ont été contrefaits afin d'obtenir l'accès. C'est ici que votre Tech ISS peut mettre des règles qui déclencheraient un verrouillage de compte ou l'auto-suppression d'un utilisateur du système auto-signin, en gardant les attaquants assez longtemps pour l'utilisateur de déterminer comment l'attaquant a réussi et comment les couper.

en guise de conclusion, assurez-vous que toute tentative de récupération, tout changement de mot de passe ou tout échec de connexion au-delà du seuil entraîne la désactivation de l'Auto-connexion jusqu'à ce que l'utilisateur valide correctement et reconnaisse que cela s'est produit.

I m'excuse si quelqu'un attendait de code donné dans ma réponse, qui ne va pas arriver ici. Je vais dire que J'utilise PHP, jQuery, et AJAX pour exécuter mes sites, et je N'utilise jamais Windows comme un serveur... jamais.

3
répondu user253780 2016-01-07 22:31:29

ma solution est comme ça. Ce n'est pas 100% pare-balles, mais je pense que ça vous sauvera pour la plupart des cas.

lorsque l'utilisateur s'est connecté créez avec succès une chaîne de caractères Avec cette information:

$data = (SALT + ":" + hash(User Agent) + ":" + username 
                     + ":" + LoginTimestamp + ":"+ SALT)

Encrypt $data , défini le type à HttpOnly et défini le cookie.

lorsque l'utilisateur revenir à votre site, faire cette étape:

  1. obtenir des données de cookie. Supprimer des personnages dangereux à l'intérieur du cookie. Explose - le avec le caractère : .
  2. contrôle de validité. Si le cookie est plus ancien que X jours puis rediriger l'utilisateur vers la page de connexion.
  3. si cookie n'est pas Ancien, obtenez le dernier changement de mot de passe de la base de données. Si le mot de passe est modifié après la dernière connexion de rediriger l'utilisateur vers la page de connexion.
  4. si pass n'a pas été changé récemment; obtenir l'agent de navigateur actuel de l'utilisateur. Vérifier si (currentUserAgentHash == cookieUserAgentHash). Si les agents sont les mêmes, passez à l'étape suivante, sinon redirigez vers la page de connexion.
  5. si toutes les étapes franchies autorisent avec succès le nom d'utilisateur.

si l'utilisateur signe, supprimez ce cookie. Créer un nouveau cookie si l'utilisateur se reconnecte.

2
répondu trante 2013-08-04 00:06:21

Je ne comprends pas le concept de stocker des choses cryptées dans un cookie quand c'est la version cryptée de celui-ci que vous avez besoin de faire votre piratage. Si je manque quelque chose, veuillez commenter.

je pense à adopter cette approche pour "se souvenir de moi". Si vous voyez des problèmes, veuillez les commenter.

  1. créez une table pour stocker les données "Remember Me" - séparée de la table d'utilisateur afin que je puisse me connecter à partir de plusieurs appareil.

  2. sur la connexion réussie (avec Remember Me ticked):

    A) générer une chaîne de caractères aléatoire unique pour être utilisé comme UserID sur cette machine: bigUserID

    B) générer une chaîne de caractères aléatoire unique: bigKey

    c) stocker un cookie: bigUserID: bigKey

    D) dans la table "Remember Me", ajouter un enregistrement avec: UserID, adresse IP, bigUserID, bigKey

  3. Si l'on tente d'accéder à quelque chose qui nécessite un nom d'utilisateur:

    A) Vérifiez le cookie et recherchez bigUserID & bigKey avec une adresse IP correspondante

    b) Si vous le trouvez, Connectez la personne mais mettez un drapeau dans la table d'utilisateur "soft login" de sorte que pour toute opération dangereuse, vous pouvez demander une connexion complète.

  4. sur la déconnexion, marquer tous les enregistrements" Remember Me " pour cet utilisateur comme expiré.

La seule vulnérabilités que je peux voir, c'est;

  • vous pouvez récupérer l'ordinateur portable de quelqu'un et falsifier son adresse IP avec le cookie.
  • vous pourriez mystifier une adresse IP différente à chaque fois et deviner tout le truc - mais avec deux grosses ficelles pour correspondre, ce serait...faire un calcul similaire à ci-dessus...Je n'ai aucune idée...énorme cote?
2
répondu Enigma Plus 2014-04-21 11:07:24

j'ai lu toutes les réponses et encore difficile à extraire de ce que j'étais censé faire. Si une image vaut 1k mots j'espère que cela aide les autres à mettre en œuvre une sécurité de stockage persistant basé sur Barry Jaspan Amélioration Persistante Cookie de Connexion de Meilleure Pratique

enter image description here

si vous avez des questions, des commentaires ou des suggestions, je vais essayer de mettre à jour le diagramme pour réfléchir pour le débutant qui essaie d'implémenter un login sécurisé et persistant.

2
répondu Josh Woodcock 2016-11-28 13:29:30

mise en Œuvre d'une "rester Connecté" signifie que vous devez définir exactement ce que cela signifie pour l'utilisateur. Dans le cas le plus simple, je dirais que cela signifie que la session a un délai beaucoup plus long: 2 jours (disons) au lieu de 2 heures. Pour ce faire, vous aurez besoin de votre propre stockage de session, probablement dans une base de données, vous pouvez définir des délais d'expiration pour les données de la session. Ensuite, vous devez assurez-vous de définir un cookie qui va rester pour quelques jours (ou plus), plutôt que d'expirer quand ils fermez le navigateur.

je vous entends vous demander " pourquoi 2 jours? pourquoi pas 2 semaines?". C'est parce que l'utilisation d'une session en PHP repoussera automatiquement l'expiration. C'est parce que l'expiration d'une session en PHP est en fait un délai inactif.

maintenant, ayant dit cela, j'implémenterais probablement une valeur de timeout plus dure que je stocke dans la session elle-même, et à environ 2 semaines, et j'ajouterais du code pour voir cela et invalider de force la session. Ou au moins pour les enregistrer hors. Cela signifie que l'utilisateur sera invité à vous connecter régulièrement. Yahoo! ne ce.

0
répondu staticsan 2009-08-31 06:00:10