it-swarm.dev

Protezione di un'app JavaScript a pagina singola con back-end RESTful

Attualmente sto costruendo una SPA JavaScript e ho cercato come proteggerla. Attualmente esiste un'API RESTful con cui interagire completamente tramite AJAX. Abbiamo anche client mobili che interagiscono con questa API e attualmente supporta solo l'autenticazione HTTP BASIC su SSL. L'app JavaScript comunicherà anche esclusivamente su SSL, ma BASIC Auth non la taglierà poiché ciò implicherebbe la memorizzazione della password (o di una sua derivata) sul client. Infine, l'app SPA sarà puro JavaScript e HTML, pubblicata sullo stesso server dell'API RESTful, ma senza alcun framework lato server.

Gol :

  • Nessun framework lato server per il client JavaScript (è solo un altro client).
  • Mantenere l'apolidia dell'API RESTful, per i motivi tipici (scalabilità, tolleranza agli errori, distribuzione semplificata, ecc.)
  • Qualsiasi stato dovrebbe essere gestito dal client. Ai fini di questa domanda, ciò significa le credenziali di accesso.
  • Lo stato di accesso gestito dal client deve essere sicuro e resistente al dirottamento della sessione e ad attacchi simili.

Quello che ho escogitato è basato sulla mia ricerca di OAuth e schemi simili (Amazon, ecc.).

  1. L'utente accederà utilizzando e HTTP POST su SSL.
  2. Il server calcolerà un hash come segue:

    HMAC (key, userId + ":" + ipAddress + ":" + userAgent + ":" + todaysDateInMilliseconds)

  3. Questo token verrà restituito al client e fornito con ogni successiva richiesta al posto di userName e password. Molto probabilmente verrà memorizzato in localStorage o in un cookie.

È sicuro? La mia motivazione per scegliere userId, ipAddress, todaysDateInMilleseconds è di creare un token valido solo per oggi, ma non richiede la ricerca del database per ogni richiesta ed è sicuro da archiviare sul client. Non posso fidarmi che la chiave non sarà compresa, quindi l'inclusione dell'indirizzo IP nel tentativo di prevenire il dirottamento della sessione.

Consentitemi di includere il seguente link da un post correlato su StackExchange perché penso che risolva molti problemi che sto cercando di risolvere: REST e Statession Session Ids

Dopo il feedback iniziale qui ho deciso di utilizzare solo i primi due ottetti dell'indirizzo IP per gestire meglio i client dietro proxy e client mobili. Non è ancora perfetto, ma è un compromesso per un po 'di sicurezza aggiuntiva.

68
Jon Wingfield

Il servizio offerto dal token è che il server riconoscerà in qualche modo il token come unico. Come può il server convalidare un token basato su HMAC? Ricalcolo, usando la sua chiave HAMC segreta e i dati su cui opera HMAC . Se si desidera che il token venga calcolato su ID utente, password, IP e data, il server deve conoscere tutte queste informazioni. Tuttavia, non si desidera che il server memorizzi la password e il client non la invierà con ogni richiesta. Come può funzionare il tuo sistema, allora?

L'idea di base, tuttavia, è solida:

  • Gli utenti "accedono" in qualsiasi modo ritenga opportuno.
  • A tale accesso, il server invia un valore di cookie, da restituire con ogni richiesta successiva (ecco cosa fanno i cookie).
  • Il cookie contiene l'ID utente, la data in cui è stato emesso e un valore m = HMAC (K, ID utente || data || IP) .
  • Quando il server riceve una richiesta, convalida il cookie: l'ID utente e la data provengono dal cookie stesso, l'IP di origine viene ottenuto dal livello del server Web e il server può ricalcolare il valore m per verificare che corrisponda a quello memorizzato nel cookie.

È possibile sostituire l'intero cookie con un ID di sessione casuale, se il server dispone di spazio di archiviazione (temporaneo). In effetti, il server potrebbe ricordare la mappatura da un ID di sessione casuale alle informazioni specifiche dell'utente (come il suo nome e indirizzo IP); l'ID sessione precedente può essere automaticamente scaduto, pertanto lo spazio di archiviazione non cresce indefinitamente. Il cookie sopra descritto è solo un modo per offload storage sul client stesso.

Nota: l'utilizzo dell'indirizzo IP può comportare alcuni problemi pratici. Alcuni client sono dietro proxy, anche proxy con bilanciamento del carico, quindi non solo l'indirizzo IP del client può essere "nascosto" (dal server, vedi l'indirizzo del proxy, non l'indirizzo del client) ma l'indirizzo IP che ottieni sul lato server potrebbe spostarsi in modo irregolare (se due richieste successive dal client hanno attraversato proxy distinti in una proxy farm).

30
Thomas Pornin

C'è una soluzione molto più semplice:

sa SSL a livello di sito, quindi usa il tracciamento della sessione standard del tuo framework.

Questo è tutto ciò che devi fare.

Più in dettaglio, l'utente inizialmente effettua l'accesso fornendo nome utente e password; viene POSTATO al server, che può verificarne la validità. Se l'autenticazione ha esito positivo, il codice del server imposta un flag nello stato della sessione ricordando che l'utente si è autenticato correttamente e ricordando il nome utente dell'utente. Tutte le richieste successive verranno eseguite nella stessa sessione, in modo da poterle autenticare facilmente e consentire loro di procedere.

(Ancora più in dettaglio: ogni volta che ricevi una richiesta, controlli lo stato della sessione per vedere se l'utente si è autenticato correttamente ed è autorizzato a eseguire questa azione. In caso affermativo, consenti la richiesta ed esegui l'azione; in caso contrario, reindirizza l'utente a una pagina di accesso o presentare qualche altro messaggio di errore.)

Si noti che questo soddisfa tutti i requisiti. Non richiede una ricerca nel database per ogni richiesta. È compatibile con un'API RESTful. È compatibile con un'app a pagina singola. Non è necessario codificare nulla di sofisticato: basta usare il supporto esistente del framework per le sessioni (di solito, utilizza un cookie di sessione con un ID sessione univoco e un meccanismo per memorizzare lo stato sul lato server associato a tale ID sessione) .

Come parte dell'utilizzo di SSL a livello di sito, è necessario impostare il contrassegno sicuro sul cookie dell'ID sessione per proteggerlo da intercettazioni (ciò garantirà che non verrà mai inviato tramite HTTP). Dovresti anche abilitare HSTS, per dire al browser di usare sempre SSL sul tuo sito. Cerca in questo sito per ulteriori informazioni su come distribuire SSL in tutto il sito.

Non si deve fare affidamento sull'indirizzo IP del client per essere statico. Può cambiare, ad esempio, se il client è mobile e si sposta da una rete wireless a un'altra. Pertanto, è meglio evitare di utilizzare l'indirizzo IP del client per qualsiasi cosa.

9
D.W.

Controlla questo post tilizzando OAuth2 in HTML5 Web App . La risposta di @jandersen fornisce una buona spiegazione sull'uso del flusso credenziali della password del proprietario della risorsa nelle applicazioni a pagina singola. In ogni caso, il flusso preferito per queste app dovrebbe essere Implicito concessione . In effetti, la risposta di @jandersen sul post di riferimento riguarda la modifica delle credenziali della password del proprietario della risorsa per agire come qualcosa di simile alla concessione implicita.

3
Daniel Cerecedo