Question

Mon application Web utilise des sessions pour stocker des informations relatives à l'utilisateur une fois qu'ils ont connecté, et de maintenir cette information qu'ils voyagent d'une page à l'intérieur de l'application. Dans cette application particulière, je stocker les user_id, first_name et last_name de la personne.

Je voudrais offrir un « Rester connecté » option Connexion qui mettra un cookie sur la machine de l'utilisateur pendant deux semaines, qui relancera leur session avec les mêmes détails lors de leur retour à l'application.

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

Était-ce utile?

La solution

OK, laissez-moi mettre ce sans ambages: si vous mettez des données utilisateur, ou quoi que ce soit à partir de données d'utilisateur dans un cookie à cet effet, que vous faites quelque chose de mal.

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

Quel est le problème avec le hachage des données utilisateur, demandez-vous? Eh bien, il se résume à la surface d'exposition et de la sécurité par l'obscurité.

Imaginez une seconde que vous êtes un attaquant. Vous voyez un cookie cryptographique défini pour le souvenir de moi sur votre session. Il est 32 caractères large. Gee. Cela peut être un MD5 ...

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

md5(salt+username+ip+salt)

Maintenant, tout un attaquant doit faire est la force brute du « sel » (ce qui est pas vraiment un sel, mais plus tard), et il peut maintenant générer tous les jetons faux qu'il veut avec un nom d'utilisateur pour son Adresse IP! Mais est difficile, à droite brute-forcer un sel? Absolument. Mais processeurs graphiques modernes sont extrêmement bon. Et à moins que vous utilisez suffisamment hasard il (le rendre assez grand), il va tomber rapidement, et avec elle les clés de votre château.

En bref, la seule chose que vous protéger est le sel, ce qui est pas vraiment vous protéger autant que vous le pensez.

Mais attendez!

Tout cela a été prédites que l'attaquant connaît l'algorithme! Si c'est un secret et confus, alors vous êtes en sécurité, non? MAUVAIS . 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 quitte le serveur, sauf pour l'ID.

Lorsque l'utilisateur se connecte, générer une grande (128 à 256 bits) jeton aléatoire. Ajoutez à cela une table de base de données qui mappe le jeton au userid, puis de l'envoyer au client dans le cookie.

Et si l'attaquant devine le jeton au hasard d'un autre utilisateur?

Eh bien, nous allons faire quelques calculs ici. Nous générons un jeton aléatoire de 128 bits. Cela signifie qu'il ya:

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

Maintenant, pour montrer comment absurdement grand que le nombre est, imaginons chaque serveur sur Internet (disons 50000000 aujourd'hui) en essayant de force brute ce nombre à un taux de 1.000.000.000 par seconde chacun. En réalité, vos serveurs fondraient sous une telle charge, mais nous allons jouer cela.

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

50 quadrillions par seconde suppositions. 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

6,8 sextillion secondes ...

Essayons de mettre cela sur le nombre plus convivial.

215,626,585,489,599 years

Ou mieux encore:

47917 times the age of the universe

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

En fait, il ne va pas à craquer.

Donc, pour résumer:

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);
}

Ensuite, 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: Ne pas utiliser le jeton ou la combinaison d'utilisateur et le jeton pour rechercher un enregistrement dans la base de données. Assurez-vous toujours chercher un enregistrement en fonction de l'utilisateur et d'utiliser une fonction de comparaison de sécurité moment de comparer le jeton tiré par les cheveux par la suite. En savoir plus sur les attaques coordonnées .

Maintenant, il 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 haute entropie). En outre, GenerateRandomToken() doit être une forte source aléatoire (mt_rand() est loin d'être assez fort. Utilisez une bibliothèque, comme RandomLib ou random_compat ou mcrypt_create_iv() avec DEV_URANDOM) ...

Le hash_equals() est d'empêcher attaques de synchronisation . Si vous utilisez une version de PHP ci-dessous PHP 5.6 la fonction hash_equals() n'est pas pris en charge. Dans ce cas, vous pouvez remplacer hash_equals() avec 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;
}

Autres conseils

  

Avis de sécurité : Fonder le cookie de un hachage MD5 de données déterministe 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 ircmaxell à cette question une approche plus sûre.

En général, je fais quelque chose comme ceci:

  1. L'utilisateur se connecte avec 'Rester connecté
  2. Créer une session
  3. Créer un cookie contenant appelé CHOSE: md5 (sel + nom d'utilisateur + ip + sel) et un cookie appelé somethingElse contenant id
  4. cookie de magasin dans la base de données
  5. L'utilisateur fait des choses et des feuilles ----
  6. retourne l'utilisateur, vérifier les cookies somethingElse, si elle existe, obtenir l'ancien hachage de la base de données pour cet utilisateur, vérification du contenu du match de cookie quelque chose avec le hachage de la base de données, ce qui devrait également correspondre avec un hachage nouvellement calculé (pour l'ip) ainsi: cookieHash == == databaseHash md5 (sel + nom d'utilisateur + ip + sel), si elles le font, goto 2, si elles ne le font pas goto 1

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

Vous pouvez également utiliser SHA1 au lieu de md5 (ou à peu près tout algorithme)

Introduction

Votre titre « Rester connecté » - la meilleure approche , il est difficile pour moi de savoir où commencer parce que si vous êtes à la recherche meilleure approche que vous auriez alors à l'examen de ce qui suit:

  • Identification
  • Sécurité

Cookies

Les cookies sont vulnérables, entre les vulnérabilités cookie de vol navigateur commun et les attaques de cross-site scripting, nous devons accepter que les cookies ne sont pas sûrs. Pour améliorer la sécurité, vous devez noter que php de setcookies a des fonctionnalités supplémentaires telles que

  

setcookie (string $ name [, string $ value [, int expireront $ = 0 [, $ path string [, domaine string $ [, bool $ secure = false [, bool $ httponly = false]]]]]])

  • sécurisé (Utilisation d'une connexion HTTPS)
  • httponly (réduire le vol d'identité par attaque XSS)

Définitions

  • Token (chaîne aléatoire et imprévisible de la longueur de n ex. / Dev / urandom)
  • Référence (chaîne aléatoire Imprévisible de longueur n, par exemple. / Dev / urandom)
  • Signature (Génère une valeur de clé de hachage en utilisant la méthode HMAC)

Approche simple

Une solution simple serait:

  • L'utilisateur est connecté avec Se souvenir de moi
  • Connectez-vous Cookie émis avec jeton et signature
  • Quand est de retour, Signature est cochée
  • Si la signature est ok .. alors nom d'utilisateur et jeton est recherché dans la base de données
  • sinon valide .. revenir à la page de connexion
  • Si elle est valide connecter automatiquement

L'étude de cas ci-dessus résume tout exemple donné sur cette page, mais ils défavorise est que

  • Il n'y a aucun moyen de savoir si les témoins ont été volés
  • Attacker peut être des opérations sensibles d'accès tels que le changement de mot de passe ou des données telles que des renseignements personnels et la cuisson etc.
  • Le cookie compromis serait toujours valable pour la durée de vie des cookies

meilleure solution

Une meilleure solution serait

  • L'utilisateur est connecté et remember me est sélectionné
  • Générer jeton et signature et stocker dans cookies
  • Les jetons sont aléatoires et ne sont valables que pour autentication unique
  • Le jeton sont remplacent à chaque visite sur le site
  • Lorsqu'un utilisateur non connecté, visitez le site de la signature, jeton et nom d'utilisateur sont vérifiées
  • Se souvenir de moi devraient avoir un accès limité et ne permet pas la modification du mot de passe, informations personnelles, etc.

Exemple de 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());
}

Class

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);
    }
}

Test dans Firefox et Chrome

entrer image description ici

Avantage

  • Une meilleure sécurité
  • Accès limité pour l'attaquant
  • Lorsque cookie est volé sa seule valable pour un accès simple
  • La prochaine fois que l'utilisateur l'accès initial du site, vous pouvez automatiquement détecter et avertir l'utilisateur de vol

Inconvénient

  • Ne supporte pas la connexion persistante via plusieurs navigateur (mobile et Web)
  • Le cookie peut encore être volé parce que l'utilisateur ne reçoit que la notification après la connexion suivante.

Quick Fix

  • Présentation du système d'approbation pour chaque système qui doit avoir une connexion persistante
  • Utilisez plusieurs cookies pour l'authentification

Multiple approche Cookie

Quand un attaquant est sur le point de voler les cookies le seul se concentrer sur un site Web ou par exemple de domaine. example.com

Mais vraiment, vous pouvez authentifier un utilisateur à partir de 2 domaines différents ( example.com et Fakeaddsite.com ) et la faire ressembler à "Annonce Cookie"

  • utilisateur connecté à example.com se souvenir de moi
  • nom d'utilisateur de magasin, jeton, référence cookies
  • nom d'utilisateur de magasin, jeton, référence dans la base de données par exemple. Memcache
  • Envoyer id refrence par get et iframe fakeaddsite.com
  • fakeaddsite.com utilise la référence pour récupérer l'utilisateur et un jeton de base de données
  • fakeaddsite.com stocke la signature
  • Lorsqu'un utilisateur retourne récupérer des informations de signature avec iframe de fakeaddsite.com
  • Combiner des données et faire la validation
  • ..... vous savez le reste

Certaines personnes peuvent se demander comment pouvez-vous utiliser 2 biscuits différents? Eh bien il est possible, imaginez example.com = localhost et fakeaddsite.com = 192.168.1.120. Si vous inspectez les cookies qu'il ressemblerait à ceci

entrer image description ici

De l'image ci-dessus

  • Le site actuel est visité localhost
  • Il contient également les cookies de 192.168.1.120

192.168.1.120

  • HTTP_REFERER accepte uniquement défini
  • accepte uniquement la connexion de REMOTE_ADDR spécifiée
  • Pas de JavaScript, Aucun, mais rien consister plutôt que signer des informations et ajouter ou récupérer de cookies

Avantage

  • 99% pour cent du temps, vous avez dupé l'attaquant
  • Vous pouvez facilement verrouiller le compte dans l'attaquant première tentative
  • attaque peut être évitée même avant la prochaine connexion comme les autres méthodes

Inconvénient

  • Demande multiple au serveur juste pour une connexion unique

Amélioration

  • Utilisation Fait ajax utilisation iframe

Il y a deux très intéressants articles, j'ai trouvé tout en recherchant une solution parfaite pour le « souvenir-moi » -problem:

J'ai demandé un angle de cette question ici , et les réponses vous mènera à tous les liens cookie timing-out basée sur des jetons dont vous avez besoin.

En fait, vous ne stockez pas le userId dans le cookie. Vous pouvez stocker un jeton unique (énorme chaîne) que l'utilisateur utilise pour venir chercher leur 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).

Je recommande l'approche mentionnée par Stefan (c.-à suivre les lignes directrices ont contribué à améliorer Connexion des cookies persistants Meilleur pratique) et recommandons également de vous assurer que vos cookies sont les cookies HttpOnly donc ils ne sont pas accessibles à, potentiellement malveillant, JavaScript.

Générer un hachage, peut-être avec un secret que vous le savez, puis le stocker dans votre base de données afin qu'il puisse être associé à l'utilisateur. Devrait fonctionner assez bien.

fil vieux, mais toujours une préoccupation valable. J'ai remarqué quelques bonnes réponses à la sécurité, et en évitant l'utilisation de la « sécurité par l'obscurité », mais les méthodes techniques réelles données ne suffisaient pas à mes yeux. Ce que je dois dire avant que je cotise ma méthode:

  • JAMAIS stocker un mot de passe en texte clair ... JAMAIS!
  • JAMAIS stocker le mot de passe haché d'un utilisateur dans plus d'un endroit dans votre base de données. Votre serveur de back-end est toujours capable de tirer le mot de passe haché de la table des utilisateurs. Ce n'est pas plus efficace pour stocker des données redondantes au lieu des opérations supplémentaires à prestations déterminées, l'inverse est vrai.
  • Votre doit être unique, donc pas de deux utilisateurs de session ID pourrait jamais partager une carte d'identité, d'où l'utilité d'un ID (pourrait votre numéro d'identification du pilote de licence jamais correspondre à une autre personne? Non.) Cela génère une combinaison unique en deux parties, sur la base de 2 chaînes uniques. Votre table Sessions devrait utiliser l'ID comme PK. Pour permettre à plusieurs appareils à faire confiance pour l'auto-signin, utilisez une autre table pour les appareils de confiance qui contient la liste de tous les appareils validés (voir mon exemple ci-dessous), et est mis en correspondance en utilisant le nom d'utilisateur.
  • Il ne sert à rien de hachage des données connues dans un cookie, peut être copié le cookie. Ce que nous recherchons est un dispositif utilisateur conforme à fournir des informations authentiques qui ne peut être obtenue sans un attaquant de compromettre la machine de l'utilisateur (encore une fois, voir mon exemple). Cela signifierait cependant qu'un utilisateur légitime qui interdit sa machine d'information statique (ie d'adresse MAC, le nom d'hôte du périphérique, useragent si limité par le navigateur, etc.) de rester cohérent (ou il usurpe en premier lieu) ne sera pas en mesure de utiliser cette fonction. Mais si cela est une préoccupation, tenir compte du fait que vous offrez automatiquement signin aux utilisateurs qui s'identifier de manière unique , donc s'ils refusent d'être connu par usurpation d'identité leur MAC, usurpation d'identité leur useragent, usurpation d'identité / changer leur nom d'hôte, se cachant derrière les proxies, etc., ils ne sont pas identifiables et ne doivent jamais être authentifiées pour un service automatique. Si vous voulez, vous devez regarder dans un accès de carte à puce fournie avec le logiciel côté client qui établit l'identité de l'appareil utilisé.

Que tout dit, il y a deux grandes façons d'avoir sur votre système auto-signin.

D'abord, le pas cher, facile qui met tout sur quelqu'un d'autre. Si vous faites votre site support connecté avec, par exemple, Google + compte, vous avez probablement un Google rationalisée + bouton qui se connectera l'utilisateur si elles 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 connecté automatiquement si elles sont déjà signés avec un authentificateur de confiance et pris en charge, et coché la case pour le faire, que vos scripts côté client exécutent le code derrière le bouton correspondant « Connexion avec » avant le chargement , juste être sûr d'avoir le magasin de serveur un identifiant unique dans une table auto-signin qui a le nom d'utilisateur, ID de session, et l'authentificateur utilisé pour l'utilisateur. Étant donné que ces signes dans les méthodes utilisent AJAX, vous attendez une réponse de toute façon, et que la réponse est soit une réponse validée ou un rejet. Si vous obtenez une réponse validée, l'utiliser comme d'habitude, puis continuer à charger l'utilisateur connecté normalement. Dans le cas contraire, la connexion a échoué, mais ne dites pas à l'utilisateur, juste continuer comme non enregistrés, ils remarqueront. Ceci est d'empêcher un attaquant qui a volé les cookies (ou les forgé dans une tentative d'escalade de privilèges) d'apprendre que les auto-utilisateur se connecte au site.

Ce ne coûte pas cher et peut être considéré comme sale par certains aussi parce qu'il tente de valider votre potentiel déjà signé en soi avec des endroits comme Google et Facebook, sans même vous dire. Il devrait cependant pas être utilisé sur les utilisateurs qui n'ont pas demandé à votre site auto-connecter, et cette méthode particulière estuniquement pour l'authentification externe, comme avec Google+ ou FB.

Comme un authentificateur externe a été utilisé pour indiquer au serveur dans les coulisses ou non un utilisateur a été validé, un attaquant ne peut pas obtenir quoi que ce soit autre qu'un identifiant unique, qui ne sert à rien lui-même. Je vais élaborer:

  • L'utilisateur site visites 'Joe' pour la première fois, Session ID placé dans cookie 'session'.
  • L'utilisateur Journaux 'Joe' dans, les privilèges dégénère, obtient un nouveau numéro de session et renouvelle cookie 'session'.
  • L'utilisateur 'joe' choisit d'auto-signin en utilisant google +, obtient un identifiant unique placé dans cookie 'keepmesignedin'.
  • L'utilisateur 'joe' a google les garder connecté, permettant à votre site pour auto-signIn l'utilisateur à l'aide de Google dans votre back-end.
  • essaie systématiquement Attacker ID unique pour « keepmesignedin » (ce qui est de notoriété publique remis à tous les utilisateurs), et n'est pas signé dans nulle part ailleurs; tente ID unique attribué à Joe.
  • Server reçoit ID unique pour 'Joe', tire match DB pour un compte Google +.
  • Le serveur envoie Attacker page de connexion qui exécute une requête AJAX à Google pour se connecter.
  • serveur Google reçoit la demande, utilise son API pour voir Attacker est pas connecté actuellement.
  • Google envoie la réponse qu'il n'y a pas actuellement connecté utilisateur via cette connexion.
  • La page de réponse reçoit Attacker, le script redirige automatiquement vers la page de connexion avec une valeur POST codée dans l'URL.
  • page de connexion obtient la valeur POST, envoie le cookie pour « keepmesignedin » à une valeur vide et valable jusqu'à la date de 01/01/1970 pour dissuader une tentative automatique, ce qui provoque le navigateur de l'Attacker simplement supprimer le cookie.
  • est Attacker given normale de connexion pour la première fois.

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

Cette méthode peut et doit être utilisé en conjonction avec votre authentificateur interne pour ceux qui vous connecter à votre site en utilisant un authentificateur externe.

=========

Maintenant, pour votre système authentificateur propre qui peut automatiquement les utilisateurs Signin, voici comment 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 est capable d'être de 255 caractères. J'ai mes noms d'utilisateur limites du programme serveur dans mon système à 32 caractères, mais authentificateurs externes peuvent avoir les noms d'utilisateur avec leur @ domain.tld être plus grand que cela, donc je soutiens que 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 d'utilisateur dans ce tableau, parce que le nom d'utilisateur, lorsque vous êtes connecté, est dans les données de session, et le programme ne permet pas des données nulles. Le id_session et session_token peuvent être générés en utilisant hash md5 aléatoire, SHA1 / 128/256 hash, timbres datetime avec des chaînes aléatoires ajoutés à eux alors hachés, ou tout ce que vous voulez, mais l'entropie de votre sortie devrait rester aussi élevée que tolérable atténuer les attaques de force brute de même à décoller, et tous les hash générés par votre classe de session doivent être vérifiés pour les matches de la table des sessions avant de tenter 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

adresses MAC par leur nature sont censés être unique, donc il est logique que chaque entrée a une valeur unique. Les noms d'hôtes, d'autre part, pourrait être dupliqué sur des réseaux séparés légitimement. Combien de personnes utilisent « Home-PC » comme l'un de leurs noms d'ordinateur? Le nom d'utilisateur est prise à partir des données de session par le backend du serveur, donc il est impossible de manipuler. En ce qui concerne le jeton, la même méthode pour générer des jetons de session pour les pages doit être utilisé pour générer des jetons dans les cookies pour l'utilisateur auto-signin. Enfin, le code datetime est ajouté lorsque l'utilisateur aurait besoin de revalider leurs pouvoirs. Soit mettre à jour cette datetime lors de la connexion de l'utilisateur maintenir dans quelques jours, ou le forcer à expirer quelle que soit la dernièrese connecter en gardant seulement pour un mois, quel que soit votre conception dicte.

Cela empêche quelqu'un d'usurper systématiquement le MAC et le nom d'hôte pour un utilisateur qu'ils connaissent des signes d'auto-in. JAMAIS ont l'utilisateur de garder un cookie avec leur mot de passe, clair ou autrement. Avez-le jeton régénérables sur chaque page de navigation, comme vous le feriez le jeton de session. Cela réduit massivement la probabilité qu'un attaquant pourrait obtenir un cookie jeton valide et l'utiliser pour vous connecter. Certaines personnes vont essayer de dire qu'un attaquant pourrait voler les cookies de la victime et faire une attaque de relecture de session pour ouvrir une session. Si un attaquant pourrait voler les cookies (ce qui est possible), ils auraient certainement compromis l'ensemble du dispositif, ce qui signifie qu'ils pourraient simplement utiliser l'appareil pour se connecter de toute façon, qui contrecarre le but de voler les cookies entièrement. Tant que votre site fonctionne sur HTTPS (ce qui devrait en traiter les mots de passe, des numéros de CC ou d'autres systèmes de connexion), vous avez donné toute la protection à 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 l'auto-signin. Vous pouvez expirer 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 devrait se poursuivre entre les sessions. Si vous voulez que les deux données de session persistants et non persistants, utilisez une autre table pour les données de session persistants avec le nom d'utilisateur comme PK, et que le serveur soit récupérer comme il les données de session normale, il suffit d'utiliser une autre variable.

Une fois la connexion a été atteint de cette façon, le serveur doit valider encore la session. C'est là que vous pouvez coder les attentes pour les systèmes volés ou compromis; 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 les cookies ont été forgés afin d'y avoir accès. C'est là votre ISS Tech peut mettre des règles qui déclencheraient un verrouillage de compte ou auto-suppression d'un utilisateur du système d'auto-signin, en gardant les attaquants assez longtemps pour que l'utilisateur de déterminer comment l'attaquant a réussi et comment les couper.

Comme une note de clôture, assurez-vous que toute tentative de récupération, des changements de mot de passe, ou les échecs de connexion depuis le résultat de seuil automatique signin être désactivé jusqu'à ce que l'utilisateur valide correctement et reconnaît cela a eu lieu.

Je suis désolé si quelqu'un attendait un code à donner dans ma réponse, cela ne va pas se passer ici. Je dirai que j'utilise PHP, jQuery et AJAX pour exécuter mes sites, et je n'utiliser Windows comme serveur ... jamais.

Ma solution est comme ça. Il est je pense pas que l'épreuve des balles à 100%, mais il vous permettra d'économiser pour la plupart des cas.

Lorsque l'utilisateur connecté créer avec succès une chaîne avec cette information:

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

Chiffrer $data, définissez le type HttpOnly et les cookies défini.

Lorsque l'utilisateur de revenir à votre site, Faites ces étapes:

  1. Obtenir des données de cookies. Retirez les caractères dangereux à l'intérieur de cookie. Exploser avec caractère :.
  2. Vérifier la validité. Si cookie est plus de X jours redirigent ensuite l'utilisateur à la page de connexion.
  3. Si cookie est pas vieux; Obtenir la dernière fois le changement de mot de passe de la base de données. Si le mot de passe est changé après le dernier utilisateur redirect connexion de l'utilisateur à la page de connexion.
  4. Si passe n'a pas été modifié récemment; Obtenez l'agent du navigateur de l'utilisateur. Vérifiez si (currentUserAgentHash == cookieUserAgentHash). Si les agents sont les mêmes vont à l'étape suivante, redirigez autre page de connexion.
  5. Si toutes les étapes avec succès passé autorisent le nom d'utilisateur.

Si signouts utilisateur, supprimer ce cookie. Créer un nouveau cookie si les connexions réutilisateur.

Je ne comprends pas le concept de stockage des choses cryptées dans un cookie quand il est la version cryptée de ce que vous devez faire votre hacking. Si je me manque quelque chose, s'il vous plaît commentaire.

Je pense à cette approche de « Se souvenir de moi ». Si vous pouvez voir toutes les questions, s'il vous plaît commentaire.

  1. Créer une table pour stocker "Remember Me" données -. Séparer à la table utilisateur afin que je puisse se connecter depuis plusieurs périphériques

  2. connexion réussie (avec Se souvenir de moi cochée):

    a) générer une chaîne aléatoire unique à utiliser comme ID utilisateur sur cette machine: bigUserID

    b) générer une chaîne aléatoire unique: bigKey

    c) un cookie: bigUserID: bigKey

    d) Dans la table "Remember Me", ajouter un enregistrement avec: ID utilisateur, adresse IP, bigUserID, bigKey

  3. Si vous essayez d'accéder à quelque chose qui nécessite une connexion:

    a) Vérifiez le cookie et la recherche de bigUserID & bigKey avec une adresse IP correspondante

    b) Si vous le trouvez, identifiez-vous la personne, mais définir un indicateur dans la table utilisateur « Connex » de sorte que pour toutes les opérations dangereuses, vous pouvez demander un login complet.

  4. On logout, Mark tous les "Remember Me" enregistrements pour cet utilisateur comme ayant expiré.

Les seules vulnérabilités que je peux voir est;

  • vous pouvez mettre la main sur l'ordinateur portable de quelqu'un et usurper leur adresse IP avec le cookie.
  • vous pouvez usurper une adresse IP différente à chaque fois et deviner la chose - mais avec deux grandes chaînes de match, ce serait ... faire un calcul semblable ci-dessus ... Je ne sais pas ... énorme chance ?

Je lis toutes les réponses et toujours trouvé difficile d'extraire ce que je devais faire. Si une image vaut mots 1k J'espère que cela aide les autres à mettre en œuvre un stockage permanent sécurisé basé sur Amélioration persistante Connexion Cookie les meilleures pratiques

Si vous avez des questions, des commentaires ou des suggestions, je vais essayer de mettre à jour le schéma de réfléchir pour les débutants d'essayer de mettre en œuvre une connexion persistante sécurisée.

Mettre en place un « Keep Me connecté » fonctionnalité signifie que vous devez définir exactement ce que cela signifie pour l'utilisateur. Dans le cas le plus simple, je l'utiliser pour signifier la session a un délai d'attente beaucoup plus longue: 2 jours (par exemple) au lieu de 2 heures. Pour ce faire, vous aurez besoin de votre propre espace de stockage de session, probablement dans une base de données, de sorte que vous pouvez définir les temps sur mesure d'expiration des données de session. Ensuite, vous devez vous assurer que vous définissez un cookie qui collera pendant quelques jours (ou plus), plutôt que fin quand ils ferment le navigateur.

Je vous entends demander « pourquoi 2 jours pourquoi pas 2 semaines? ». En effet, à l'aide d'une session en PHP sera automatiquement repousser l'expiration de retour. En effet, l'expiration d'une session en PHP est en fait un délai d'inactivité.

Maintenant, après avoir dit, je serais probablement mettre en œuvre une valeur de délai d'attente plus difficile que je stocke dans la session elle-même, et en 2 semaines environ, et ajouter du code pour voir que et invalident force la session. Ou au moins pour les déconnecter. Cela signifie que l'utilisateur sera invité à se connecter régulièrement. Yahoo! le fait.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top