Autenticazione di un utente mediante verifica di una firma

1

Sfondo

Sto configurando un'API che verrà utilizzata principalmente su HTTPS (solo le chiamate che non necessitano di alcuna sicurezza, quali che siano sempre disponibili su HTTP). Alcuni aspetti di esso devono essere accessibili solo da utenti autenticati. Per consentire questo senza usare password, ogni utente possiede uno o più keypair RSA. La chiave pubblica viene mantenuta sul server API.

Quando l'utente vuole essere autenticato, firma il timestamp corrente con la sua chiave privata e lo invia, il timestamp e un ID a quale coppia di chiavi è stata utilizzata sul server.

Il server verifica che il messaggio (il timestamp) sia stato firmato da un utente con la chiave corrispondente.

Il server verifica che il timestamp non abbia superato una certa quantità di tempo e restituisca un token JWT firmato con la chiave privata del server che verrà utilizzata in seguito per autenticare l'utente.

Le preoccupazioni

Il timestamp (che funge da sostantivo (?) e un modo per limitare l'accesso in base al tempo) non deve essere inviato insieme alla richiesta di autenticazione al server, poiché sapendo quale messaggio è stato firmato, la chiave potrebbe essere decodificata.

Un utente poco prudente potrebbe sbagliare una chiave firmata che sarebbe praticamente altrettanto grave di perdere una password se non peggio.

Domanda

È sbagliato fornire il "nonce" che è stato firmato insieme alla richiesta o il server dovrebbe "sapere" (tramite uno scambio precedente)?

Usando il timestamp come messaggio quando si creano i digest rogue della sconfitta della firma? Cioè è sufficiente per rendere il digest inutilizzabile dopo il tempo scaduto - poiché il messaggio non può essere modificato senza passare una verifica?

    
posta Alex 18.01.2016 - 17:26
fonte

1 risposta

1

Non mi è chiaro esattamente il motivo per cui stai implementando un meccanismo di autenticazione così complesso. Le soluzioni di autenticazione homegrown sono notoriamente difficili da correggere. Quindi i miei primi pensieri sono di cercare di guidarvi verso meccanismi più standard.

In sintesi, la mia raccomandazione è di usare username / password per l'autenticazione. Se hai una buona ragione per non farlo, usa l'autenticazione reciproca SSL. E se hai davvero un buon motivo per non farlo, usa il tuo metodo suggerito con la modifica del timestamp su un nonce generato sul lato server.

Dettagli segui ...

Opzione 1: usa semplicemente nome utente / password per l'autenticazione. Non menzioni il motivo per cui non stai scegliendo questo percorso più comune. Forse stai sperando in un più alto grado di sicurezza?

Opzione 2: utilizza l'autenticazione reciproca TLS / SSL . Questo è un vero e provato standard supportato da quasi tutti i browser Web e la libreria TLS. Nell'autenticazione reciproca, il client ha una chiave privata e un certificato X.509, simile al server. Quando viene avviata la connessione SSL, utilizza non solo il certificato del server, ma anche quello del client. Entrambi i lati della comunicazione possono confermare il partito con cui stanno comunicando. A differenza del certificato del server, il certificato del cliente non deve necessariamente essere firmato da un'autorità di certificazione. Ciò significa che potrebbe essere un certificato autofirmato o creato dalla tua autorità di certificazione. Tutto ciò che conta è che il server possa convalidare che è il certificato giusto per un utente specifico. La mia preferenza è semplicemente di memorizzare il certificato (in realtà l'impronta digitale del certificato) nel database degli utenti. Ciò consente una revoca semplice poiché significa semplicemente eliminare il certificato revocato dal DB.

In base alla comprensione limitata del tuo progetto, non vedo alcun vantaggio per la tua soluzione proposta rispetto all'autorizzazione reciproca SSL. Stai ricreando parti del protocollo di autenticazione reciproca invece di utilizzare solo una soluzione consolidata.

Opzione 3: la tua soluzione di homegrown. Non vedo problemi a passare il nonce nello stesso messaggio della firma. Dato che questo viene fatto su SSL, solo il client e il server potrebbero vedere queste informazioni. Quindi non importa se il server ottiene il nonce nel messaggio o "conosce" il nonce da una parte precedente della conversazione. In entrambi i casi, il server ha sia il nonce che la sua firma e nessun altro dovrebbe avere accesso a queste informazioni.

Per quanto riguarda la sconfitta di un attacco di replay (cosa presumo tu intenda per "rogue digest"), sono non entusiasta dell'utilizzo di un nonce generato dal lato client. Penso che sia più sicuro avere il server che passa il nonce al client e poi lasciare che il client firmi quei dati. Ciò richiede un ulteriore giro di comunicazione, ma poiché stiamo discutendo di conversazioni longeve in questo scenario, penso che questo dovrebbe essere OK. Una volta che ti sposti con un nonce scelto dal lato server, puoi semplicemente utilizzare un numero casuale crittograficamente sicuro come nonce e store questo nonce sul server. Il server può quindi gestire la durata di vita del nonce. Inoltre, non sono un grande fan dell'utilizzo di timestamp che si estendono su computer come, anche nel 2016, la sincronizzazione dell'orologio tra server e client può essere una seccatura.

    
risposta data 20.01.2016 - 00:26
fonte

Leggi altre domande sui tag