Sto costruendo il back-end per un'app web. Quando un nuovo utente accede al sito e fa clic sul pulsante Iscriviti , verrà compilato un modulo super semplice chiedendo loro il nome utente + la password e invieranno. Questo richiede al server di inviare una email di verifica a quell'indirizzo email. Verranno quindi controllati tramite e-mail, facendo clic su un collegamento (che verifica la loro e-mail) e quindi indirizzati alla pagina di accesso in modo che possano accedere se lo desiderano.
Per verificare la loro posta elettronica, quando il server genera l'e-mail dovrà creare (e memorizzare) un token di verifica (probabilmente un UUID) e allegarlo a questo link nell'e-mail, in modo che il collegamento abbia un aspetto simile a:
Dove vt=12345
è il "token di verifica" (probabilmente un UUID). Quindi l'utente fa clic su questo link e il mio GET v1/users/verify
endpoint esamina il token, in qualche modo conferma la sua validità e rende alcuni aggiornamenti DB per "attivare" l'utente. Ora possono accedere.
Scenari simili per quando un utente desidera annullare l'iscrizione alla posta elettronica o quando non è in grado di ricordare la propria password e deve ripristinarla in modo che possano accedere.
Cancella
L'utente vuole smettere di ricevere email ma vuole comunque utilizzare l'app. Fanno clic su un link " Annulla iscrizione " in una newsletter settimanale che inviamo loro. Questo link deve contenere una sorta di "token di annullamento sottoscrizione" simile che, come il token di verifica sopra, viene generato + memorizzato sul server e utilizzato per autenticare la richiesta dell'utente di annullare l'iscrizione via email.
Recupera password
Qui l'utente ha dimenticato la sua password e ha bisogno di recuperarla. Quindi, nella schermata di accesso, fanno clic sul collegamento " Hai dimenticato la password " e vengono presentati con un modulo in cui devono compilare il proprio indirizzo email. Il server invia una e-mail a quell'indirizzo. Controllano questa e-mail e contiene un link a un modulo dove possono inserire la loro nuova password. Questo link deve contenere un "token password di reimpostazione" che, come il token di verifica sopra, viene generato + memorizzato sul server e utilizzato per autenticare la richiesta dell'utente di cambiare la password.
Quindi qui abbiamo tre problemi molto simili da risolvere, tutti che richiedono l'uso di ciò che chiamo " token di sicurezza una tantum (OTO) ". Questi token OTO:
- Deve essere generato lato server e persistente (forse in una tabella
security_tokens
) - Deve essere qualcosa che può essere allegato ai link che esporremo dall'interno delle email
- Deve essere valido una sola volta: una volta cliccato, il token è "usato" e non può essere riutilizzato
La mia domanda
La soluzione che ho trovato era semplice ... quasi troppo semplice.
Per i token sto solo generando UUID casuali (36 caratteri) e li memorizzo in una tabella security_tokens
con i seguenti campi:
[security_tokens]
---
id (PK)
user_id (FK to [users] table)
token (the token itself)
status (UNCLAIMED or CLAIMED)
generated_on (DATETIME when created)
Quando il server li crea sono "UNCLAIMED". Quando l'utente fa clic su un collegamento all'interno della tabella, viene "CLAIMATO". Un lavoro di background worker verrà eseguito periodicamente per ripulire eventuali token CLAIMED o per eliminare tutti i token UNCLAIMED che sono "scaduti" (in base ai relativi campi generated_on
). L'app ignorerà anche tutti i token che sono stati precedentemente accreditati (e non sono ancora stati puliti).
I penso questa soluzione potrebbe funzionare, ma non sono un super-ragazzo di sicurezza e sono preoccupato che questo approccio:
- Forse lascia aperta la mia app a qualche tipo di attacco / exploit; e
- Forse reinventa la ruota quando qualche altra soluzione potrebbe funzionare altrettanto bene
Come per il 2 ° in alto mi chiedo se dovrei usare un meccanismo hash / HMAC / JWT invece di un UUID morto. Forse ci sono alcuni esperti di criptazione / sicurezza che hanno trovato un modo per far sì che questi token contengano lo stato CLAIM e la data di scadenza stessi in modo sicuro / immutabile, ecc.