Protezione di una singola pagina JavaScript con RESTful backend

65

Al momento sto sviluppando una SPA JavaScript e sto studiando come metterla al sicuro. Al momento, esiste un'API RESTful che viene completamente interagita con AJAX. Disponiamo inoltre di client mobili che interagiscono con questa API e al momento supporta solo l'autenticazione BASIC HTTP su SSL. L'app JavaScript comunicherà anche esclusivamente su SSL, ma BASIC Auth non lo taglierà in quanto ciò implicherebbe la memorizzazione della password (o una sua derivazione) sul client. Infine, l'app SPA sarà pura JavaScript e HTML, servita sullo stesso server dell'API RESTful, ma senza alcun framework lato server.

Obiettivi :

  • 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 cliente. Ai fini di questa domanda, si intendono le credenziali di accesso.
  • Lo stato di accesso gestito dal client deve essere sicuro e resistere al dirottamento di sessione e ad attacchi simili.

Ciò che ho scoperto si basa sulla mia ricerca su OAuth e schemi simili (Amazon, ecc.).

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

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

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

Questo è sicuro? La mia motivazione per la scelta di userId, ipAddress, todaysDateInMilleseconds è di creare un token che è valido solo per oggi, ma non richiede la ricerca del database per ogni richiesta E è sicuro di essere memorizzato sul client. Non posso fidarmi che la chiave non sarà comprimibile, quindi l'inclusione di indirizzo IP nel tentativo di impedire il dirottamento di sessione.

Consentitemi di includere il seguente link da un post correlato su StackExchange perché penso che risolva molti dei problemi che sto cercando di risolvere: ID sessione e ID sessione senza stato

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

    
posta Jon Wingfield 01.09.2012 - 21:46
fonte

3 risposte

29

Il servizio offerto dal token è che il server riconoscerà in qualche modo il token come uno dei suoi. Come può il server convalidare un token basato su HMAC? Ricomponendolo, utilizzando la sua chiave HAMC segreta e i dati su cui HMAC opera . Se si desidera che il token venga calcolato su userID, password, IP e data, il server deve conoscere tutte le informazioni. Tuttavia, non si desidera che il server memorizzi la password e il client non la invierà di nuovo ad ogni richiesta. Come può il tuo sistema funzionare, quindi?

L'idea di base, tuttavia, è il suono:

  • Gli utenti "accedono" in qualsiasi modo che ritieni opportuno.
  • A seguito di tale accesso, il server invia un valore del cookie, da restituire con ogni richiesta successiva (è ciò che fanno i cookie).
  • Il cookie contiene l'ID utente, la data di emissione e un valore m = HMAC (K, userID || date || 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.

Potresti sostituire l'intero cookie con un ID di sessione casuale, se il server ha uno spazio di archiviazione (temporaneo). In effetti, il server poteva ricordare la mappatura da un ID di sessione casuale alle informazioni specifiche dell'utente (come il suo nome e l'indirizzo IP); il vecchio ID di sessione può essere automaticamente scaduto, quindi lo spazio di archiviazione non cresce indefinitamente. Il cookie sopra descritto è solo un modo per scaricare l'archivio sul client stesso.

Nota: l'uso dell'indirizzo IP può comportare alcuni problemi pratici. Alcuni client sono dietro proxy, persino proxy load-balanced, quindi non solo l'indirizzo IP del client può essere "nascosto" (dal server, si vede l'indirizzo del proxy, non l'indirizzo del client) ma l'indirizzo IP che si ottiene lato server potrebbe spostarsi in modo errato (se due richieste successive dal client sono passate attraverso proxy distinti in una proxy farm).

    
risposta data 01.09.2012 - 22:12
fonte
8

C'è una soluzione molto più semplice:

Utilizza SSL in tutto il sito, quindi utilizza il monitoraggio della sessione standard del tuo framework.

Questo è tutto ciò che devi fare.

Più in dettaglio, l'utente accede inizialmente fornendo nome utente e password; viene inviato 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 con successo e ricorda il nome utente dell'utente. Tutte le richieste successive si svolgeranno nella stessa sessione, quindi puoi facilmente autenticarle e consentire loro di procedere.

(Ancora più dettagli: ogni volta che si riceve una richiesta, si controlla lo stato della sessione per vedere se l'utente è stato autenticato correttamente ed è autorizzato a eseguire questa azione.Se sì, si accetta la richiesta ed è possibile eseguire l'azione; , reindirizza l'utente a una pagina di accesso o presenta un altro messaggio di errore.)

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

Come parte dell'utilizzo di SSL in tutto il sito, dovresti impostare il flag sicuro sul tuo cookie ID di sessione, per proteggerlo da intercettazioni (questo assicurerà che non sarà 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 dovresti fare affidamento sull'indirizzo IP del client per essere statico. Potrebbe cambiare, ad esempio se il client è mobile e passa da una rete wireless a un'altra. Pertanto, è meglio evitare di utilizzare l'indirizzo IP del client per qualsiasi cosa.

    
risposta data 02.09.2012 - 01:50
fonte
2

Controlla questo post Utilizzo di OAuth2 nell'app Web HTML5 . La risposta di @jandersen fornisce una buona spiegazione sull'uso delle credenziali della password del proprietario di risorse nelle applicazioni a singola pagina. In ogni caso, il flusso preferito per questa app deve essere la sovvenzione implicita . Infatti, la risposta di @jandersen sul post di riferimento riguarda il tweaking delle credenziali della password del proprietario di risorse per agire come qualcosa vicino alla concessione implicita.

    
risposta data 07.03.2014 - 10:46
fonte

Leggi altre domande sui tag