Je souhaite ajouter une case à cocher "Se souvenir de moi" avant de me connecter.
Quelle est la meilleure façon de stocker en toute sécurité un cookie dans le navigateur de l'utilisateur?
Par exemple, Facebook a sa case à cocher "se souvenir de moi" de sorte que chaque fois que vous entrez sur facebook.com, vous êtes déjà connecté.
Ma connexion actuelle utilise des sessions simples.
Mise à jour (2017-08-13) : Pour comprendre pourquoi nous séparons
selector
ettoken
, au lieu de en utilisant simplement untoken
, veuillez lire cet article sur le fractionnement des jetons pour empêcher les attaques de synchronisation sur les requêtes SELECT.
Je vais extraire la stratégie décrite dans ce billet de blog sur l'authentification sécurisée à long terme car cela couvre beaucoup de terrain et nous ne sommes intéressés que par le "souvenez-vous de moi" pièce.
Nous voulons une table distincte 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 points importants ici sont que selector
et token
sont des champs séparés.
Si vous n'avez pas random_bytes()
, récupérez simplement 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)
]
);
}
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
}
}
Nous utilisons 9 octets de données aléatoires (base64 encodé à 12 caractères) pour notre sélecteur. Cela fournit 72 bits d'espace de clés et donc 236 bits de résistance aux collisions (attaques d'anniversaire), ce qui est supérieur à notre capacité de stockage (integer(11) UNSIGNED
) par un facteur de 16.
Nous utilisons 33 octets (264 bits) de caractère aléatoire pour notre authentificateur réel. Cela devrait être imprévisible dans tous les scénarios pratiques.
Nous stockons un hachage SHA256 de l'authentificateur dans la base de données. Cela réduit le risque d'usurpation d'identité de l'utilisateur suite à des fuites d'informations.
Nous recalculons le hachage SHA256 de la valeur d'authentificateur stockée dans le cookie de l'utilisateur, puis le comparons avec le hachage SHA256 stocké en utilisant hash_equals()
pour éviter les attaques de synchronisation.
Nous avons séparé le sélecteur de l'authentificateur car les recherches de base de données ne sont pas à temps constant. Cela élimine l'impact potentiel des fuites de synchronisation sur les recherches sans provoquer de perte de performances drastique.
Cette question est souvent posée, voici quelques liens pour vous.
Il y a également d'excellentes ressources collectées dans la réponse à cette question: Le guide définitif de l'authentification de sites Web