Question

    

Cette question a déjà une réponse ici:

         

Je voudrais ajouter un « souvenir de moi » option case à cocher avant de vous connecter.

Quelle est la meilleure façon de stocker en toute sécurité un cookie dans le navigateur de l'utilisateur?

Par exemple, Facebook ont ??leur « remember me » case à cocher pour que chaque fois que vous entrez facebook.com vous êtes déjà connecté.

Mon connexion actuelle utilise des sessions simples.

Était-ce utile?

Autres conseils

  

Mise à jour (13/08/2017) : Pour comprendre pourquoi nous séparer selector et token, au lieu d'utiliser un token, s'il vous plaît lire cet article sur le partage des jetons pour prévenir les attaques de synchronisation sur les requêtes SELECT.

Je vais extraire la stratégie décrite dans ce billet de blog à propos de sécuriser d'authentification à long terme, car qui couvre beaucoup de terrain et nous sommes seulement intéressés à la "remember me" partie .

Préambule - Structure de base de données

Nous voulons une table séparée de la table de nos utilisateurs qui ressemble à ceci (MySQL):

CREATE TABLE `auth_tokens` (
    `id` integer(11) not null UNSIGNED AUTO_INCREMENT,
    `selector` char(12),
    `token` char(64),
    `userid` integer(11) not null UNSIGNED,
    `expires` datetime,
    PRIMARY KEY (`id`)
);

Les choses importantes ici sont que selector et token sont des champs séparés.

Une fois connecté

Si vous n'avez pas random_bytes(), il suffit de prendre une copie de random_compat .

if ($login->success && $login->rememberMe) { // However you implement it
    $selector = base64_encode(random_bytes(9));
    $authenticator = random_bytes(33);

    setcookie(
        'remember',
         $selector.':'.base64_encode($authenticator),
         time() + 864000,
         '/',
         'yourdomain.com',
         true, // TLS-only
         true  // http-only
    );

    $database->exec(
        "INSERT INTO auth_tokens (selector, token, userid, expires) VALUES (?, ?, ?, ?)", 
        [
            $selector,
            hash('sha256', $authenticator),
            $login->userId,
            date('Y-m-d\TH:i:s', time() + 864000)
        ]
    );
}

réauthentifier Sur chargement de la page

if (empty($_SESSION['userid']) && !empty($_COOKIE['remember'])) {
    list($selector, $authenticator) = explode(':', $_COOKIE['remember']);

    $row = $database->selectRow(
        "SELECT * FROM auth_tokens WHERE selector = ?",
        [
            $selector
        ]
    );

    if (hash_equals($row['token'], hash('sha256', base64_decode($authenticator)))) {
        $_SESSION['userid'] = $row['userid'];
        // Then regenerate login token as above
    }
}

Détails

Nous utilisons 9 octets de données aléatoire (base64 à 12 caractères) pour notre sélecteur. Ceci permet d'obtenir 72 bits de keyspace et donc 2 36 de bits de résistance à la collision (attaques d'anniversaire), qui est plus grand que notre par un facteur de 16 capacité de stockage (integer(11) UNSIGNED).

Nous utilisons 33 octets (264 bits) de hasard pour notre authentificateur réelle. Cela devrait être imprévisible dans tous les scénarios pratiques.

Nous conservons un hachage SHA256 de l'authentificateur dans la base de données. Cela atténue le risque d'usurpation d'identité d'utilisateur suivant les fuites d'informations.

Nous recalculons le hachage SHA256 de la valeur stockée dans authentificateur puis le cookie de l'utilisateur comparer avec le hachage SHA256 stockée à l'aide hash_equals() pour prévenir les attaques de synchronisation.

Nous avons séparé le sélecteur de la authentificateur parce que DB ne sont pas lookups à temps constant. Cela permet d'éliminer le potentiel d'impact des fuites de synchronisation sur les recherches sans causer un coup drastique de la performance.

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