Sto lavorando a un'API per un servizio REST che sto per produrre e consumare. Ho passato gli ultimi giorni a cercare di capire come gestire l'autenticazione in modo corretto e penso di aver finalmente escogitato qualcosa.
Sto arrivando a questo sulla base dei seguenti fatti sullo stack dell'applicazione:
- Client e server sono in .NET4 (parte client nel profilo client)
- Il server espone usando WCF REST
- Non voglio davvero conservare il nome utente e la password nell'app
Da 3, volevo usare una forma di autenticazione token, in modo che dopo che le credenziali sono state verificate dal server, il client ottiene un token di nuovo da usare in tutto il resto dell'app (questo mi permetterà di fare altre cose, come timeout degli utenti, essere in grado di spostarli senza soluzione di continuità tra le versioni web e desktop, ecc.). Dopo aver capito come rendere le chiamate replay e antimanomissione, ho pensato a quanto segue:
- Prima che il client tenti di autenticarsi, genera una coppia di chiavi Diffie-Hellman usando la
ECDiffieHellmanCng
classe. - Invia la parte pubblica della coppia di chiavi sul filo insieme al nome utente e alla password (ovviamente su HTTPS).
- Il server autentica la combinazione nome utente / password, se ha esito positivo, procede come segue:
- Crea un token di sessione unico
- Genera la propria coppia di chiavi DH e calcola il segreto condiviso dalla chiave pubblica fornita dal client
- Annota il token di sessione, il segreto condiviso, l'utente e l'ora "ultima azione" (utilizzata per una finestra di scadenza a rotazione) nel suo database
- Restituisce il token di sessione, la sua chiave DH pubblica e un messaggio di successo dell'autenticazione
- Il client prende la chiave DH dalla risposta, calcola il segreto condiviso e memorizza sia il token che il segreto in memoria.
Da questo punto in poi, la combinazione token / segreta di sessione funziona come la maggior parte delle altre API REST, con la richiesta di impronte digitali e timestamp, e quindi genera una sorta di HMAC. Ogni volta che un client esegue un'azione sul server, controlla la coppia token / segreta e consente l'azione se è valida e non scaduta e aggiorna l'ultimo record di azioni nella sessione.
Non vedo alcun difetto ovvio, e probabilmente è troppo ingegnerizzato per questo, ma ho bisogno di imparare come farlo ad un certo punto. L'HMAC previene gli attacchi replay, la negoziazione DH aiuta a prevenire gli attacchi MITM (non riesco a pensare a un attacco praticabile dalla cima della mia testa tra HMAC / DH).
Qualche buco che qualcuno può fare in questo?