PHP sistema di login: Remember Me (cookie permanenti) [duplicato]
-
01-10-2019 - |
Domanda
Questa domanda ha già una risposta qui:
- “Resta collegato” - l'approccio migliore 12 risposte
Vorrei aggiungere un "Ricordati di me" opzione casella di controllo prima di accedere.
Qual è il modo migliore per archiviare in modo sicuro un cookie nel browser dell'utente?
Per esempio, Facebook hanno il loro casella di controllo "ricordati di me", in modo che ogni volta che si entra facebook.com si è già connessi a.
Il mio login corrente utilizza le sessioni semplici.
Soluzione
Questa domanda viene chiesto molto, ecco alcuni link per voi.
- Best Practice per implementare sicuro “Ricordati di me”
- “Ricordami su questo computer” - Come dovrebbe funzionare?
- “Resta collegato” - l'approccio migliore
Ci sono anche alcune grandi risorse raccolte insieme nella risposta a questa domanda: The Definitive Guide all'autenticazione Sito
Altri suggerimenti
Aggiornamento (2017/08/13) : Per capire il motivo per cui stiamo separando
selector
etoken
, invece di utilizzare untoken
, si prega di leggere questo articolo su splitting gettoni per prevenire attacchi di temporizzazione su query SELECT.
ho intenzione di estrarre la strategia delineata in questo post del blog a proposito di garantire a lungo termine l'autenticazione dato che copre un sacco di terra e siamo interessati solo nel "ricordati di me" parte .
Preambolo - Struttura del database
Vogliamo un tavolo separato dalla tavola dei nostri utenti che assomiglia a questo (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`)
);
Le cose importanti sono che selector
e token
sono campi separati.
Dopo l'accesso
Se non si dispone di random_bytes()
, basta prendere una copia di 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)
]
);
}
Re-Autenticazione On caricamento della pagina
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
}
}
Dettagli
Usiamo 9 byte di dati casuali (base64 codificato a 12 caratteri) per il nostro selettore. Questo fornisce 72 bit di spazio delle chiavi e quindi 2 36 bit di resistenza collisione (attacco del compleanno), che è più grande della nostra capacità di stoccaggio (integer(11) UNSIGNED
) per un fattore di 16.
Usiamo 33 byte (264 bit) di casualità per il nostro autenticatore effettivo. Questo dovrebbe essere imprevedibile in tutti gli scenari pratici.
memorizzare un hash SHA256 del autenticatore nel database. Questo riduce il rischio di rappresentazione utente a seguito di perdite di informazioni.
Abbiamo ri-calcolare l'hash SHA256 del valore autenticatore memorizzato nel cookie dell'utente poi confrontarlo con l'hash SHA256 memorizzato utilizzando hash_equals()
per prevenire attacchi di temporizzazione.
separava il selettore dalla autenticatore perché ricerche DB non sono a tempo costante. Questo elimina la potenziale impatto delle perdite di sincronizzazione su ricerche senza causare un calo di prestazioni drastica.