Il token deve avere almeno 72 bit di entropia (9 byte o 12 caratteri Base64)
Questo dovrebbe essere generato con un PSRNG sicuro (generatore di numeri casuali). Quindi non usare il semplice operatore rand()
del tuo linguaggio di programmazione poiché potrebbe essere prevedibile, ma cerca il generatore casuale sicuro che PHP fornisce internamente, o leggi byte da /dev/urandom
store the generated links in a database table
È meglio non memorizzare il token normale nel database, nel caso in cui il database sia parzialmente rubato. Invece, memorizza un hash SHA-256 del token, in modo che l'unica copia del token originale si trovi nell'e-mail che hai inviato al cliente.
Si noti che Hashing è comune anche per le password, ma dato che le password hanno meno entropia normalmente si usa BCrypt. Poiché i token hanno 72 bit di entropia, l'hash SHA veloce andrà bene.
both token and customer id in the URL
in case the token does not match the one stored for the customer id, reset the token (to avoid brute forcing)
Direi che non è necessario. Con 72 bit di entropia, sarà praticamente impossibile forzare il token con forza bruta.
Anche questo schema suggerisce che qualsiasi persona non autorizzata possa resettare i token in questo modo, che è una forma di attacco DOS. (non hackerare, ma impedire ad altri di essere in grado di usare il sistema)
make the links one use only
Questa è una buona scelta, perché il link verrà memorizzato nella cronologia del browser, purtroppo.
set an expiration time on the links
Sicuramente una buona idea.
Tuttavia, tieni presente che l'anello più debole è la possibilità per qualcuno di hackerare l'email del cliente (che di solito è sincronizzata su più dispositivi), quindi non è una sicurezza sufficiente per molte situazioni, ma potrebbe essere accettabile nel tuo caso. Questa è la tua decisione.
I'm looking for any recommendation on this approach, and how can I improve it ? What did I miss ? What are the risks left with such approach and how to overcome them ?
Ho delineato ciò che ti sei perso sopra e il rischio principale di utilizzare questo approccio in generale. Tuttavia, vorrei aggiungere che è necessario limitare la quantità di e-mail che una persona riceverà. Non vuoi che un robot compili il tuo messaggio di Password dimenticata troppe volte, inviando spam al tuo cliente.
Ci sono molte altre considerazioni sulla sicurezza relative alla gestione delle sessioni e all'autenticazione stessa, ma questo va oltre lo scopo di questa risposta.