Perché esiste un flusso "Codice di autorizzazione" in OAuth2 quando il flusso "Implicito" funziona così bene?


264

Con il flusso "Implicito" il client (probabilmente un browser) otterrà un token di accesso, dopo che il proprietario della risorsa (ovvero l'utente) ha concesso l'accesso.

Con il flusso "Codice di autorizzazione", tuttavia, il client (in genere un server Web) ottiene un codice di autorizzazione solo dopo che il proprietario della risorsa (ovvero l'utente) ha concesso l'accesso. Con quel codice di autorizzazione il client effettua quindi un'altra chiamata all'API passando client_id e client_secret insieme al codice di autorizzazione per ottenere il token di accesso. Tutto ben descritto qui .

Entrambi i flussi hanno lo stesso esatto risultato: un token di accesso. Tuttavia, il flusso "implicito" è molto più semplice.

La domanda: perché preoccuparsi del flusso del "Codice di autorizzazione", quando le giunzioni del flusso "implicito" vanno bene? Perché non utilizzare anche "Implicito" per il server web?

È più lavoro sia per il provider che per il client.



1
Grazie, leggilo già. Non risponde alla domanda però.
Aron Woost,

1
Buona domanda in realtà e raramente ha risposto :) Vedi sotto.
Nicolas Garnier,

1
@AronWoost Penso che tu fraintenda l'app Web del server e l'app del browser
onmyway133

@entropy Questa era la mia domanda; perché non usare il flusso del browser anche per il server.
Aron Woost,

Risposte:


293

tl; dr: tutto questo per motivi di sicurezza.

OAuth 2.0 voleva soddisfare questi due criteri:

  1. Si desidera consentire agli sviluppatori di utilizzare l'URI di reindirizzamento non HTTPS perché non tutti gli sviluppatori dispongono di un server abilitato SSL e, in tal caso, non è sempre configurato correttamente (certificati SSL non autofirmati, attendibili, orologio server sincronizzato ...).
  2. Non vuoi che gli hacker siano in grado di rubare l'accesso / aggiornare i token intercettando le richieste.

Dettagli sotto:

Il flusso implicito è possibile solo in un ambiente browser per motivi di sicurezza:

Nel flusso implicito il token di accesso viene passato direttamente come frammento di hash (non come parametro URL). Una cosa importante del frammento di hash è che, una volta seguito un collegamento contenente un frammento di hash, solo il browser è a conoscenza del frammento di hash. I browser passano il frammento di hash direttamente alla pagina Web di destinazione (l'URI di reindirizzamento / la pagina Web del client). Il frammento di hash ha le seguenti proprietà:

  • Non fanno parte della richiesta HTTP, pertanto non possono essere letti dai server e per questo motivo non possono essere intercettati da server / router intermedi (questo è importante).
  • Esistono solo sul browser - lato client - quindi l'unico modo per leggere il frammento di hash è usare JavaScript che gira sulla pagina.

Ciò consente di passare un token di accesso direttamente al client senza il rischio che venga intercettato da un server intermedio. Questo ha il solo avvertimento di essere possibile solo sul lato client e richiede javascript in esecuzione sul lato client per utilizzare il token di accesso.

Il flusso implicito presenta anche problemi di sicurezza che richiedono ulteriore logica per risolvere il problema / evitare ad esempio:

  • Un utente malintenzionato potrebbe ottenere un token di accesso da un utente su un altro sito Web / app (supponiamo che sia il proprietario dell'altro sito Web / app), registrare il token sul proprio sito Web e quindi passarlo come parametro URL sul proprio sito Web quindi impersonare l'utente sul tuo sito web. Per evitare ciò, è necessario controllare l'ID client associato al token di accesso (ad esempio per Google è possibile utilizzare l'endpoint tokeninfo) per assicurarsi che il token sia stato emesso con il proprio ID client (ovvero dalla propria app) o controllare la firma se si utilizza un IDToken (ma ciò richiede il segreto del client).
  • Se la richiesta di autenticazione non ha avuto origine dalla tua proprietà (chiamata attacchi di fissazione della sessione), per evitarlo ti consigliamo di generare un hash casuale dal tuo sito Web, salvarlo in un cookie e passare lo stesso hash nel parametro URL di stato di la richiesta di autorizzazione, quando l'utente ritorna controlla il parametro di stato con il cookie e deve corrispondere.

Nel flusso del codice di autorizzazione non è possibile passare un token di accesso direttamente in un parametro URL poiché i parametri URL fanno parte della richiesta HTTP, pertanto qualsiasi server / router intermedio attraverso il quale passerebbe la richiesta (potrebbero essere centinaia) potrebbe essere in grado di leggere il token di accesso se non si utilizza una connessione crittografata (HTTPS) che consente i cosiddetti attacchi man-in-the-middle.

In teoria, il passaggio del token di accesso direttamente in un parametro URL potrebbe essere possibile, ma l'autorità dovrebbe assicurarsi che l'URI di reindirizzamento stia utilizzando HTTPS con crittografia TLS e un certificato SSL "attendibile" (in genere da un'autorità di certificazione che non è gratuita) per essere sicuri che il server di destinazione sia legittimo e che la richiesta HTTP sia completamente crittografata. Avere tutti gli sviluppatori che acquistano un certificato SSL e configurare correttamente SSL sul loro dominio sarebbe un grosso problema e rallenterebbe notevolmente l'adozione. Questo è il motivo per cui viene fornito un "codice di autorizzazione" intermedio usa e getta che solo il legittimo destinatario sarà in grado di scambiare (perché è necessario il segreto del cliente) e che il codice sarà inutile per i potenziali hacker che intercettano le richieste su transazioni non crittografate (perché non

Potresti anche sostenere che il flusso implicito è meno sicuro, ci sono potenziali vettori di attacco come lo spoofing del dominio al reindirizzamento, ad esempio dirottando l'indirizzo IP del sito Web del client. Questo è uno dei motivi per cui il flusso implicito garantisce solo token di accesso (che dovrebbero avere un uso limitato nel tempo) e non aggiorna mai token (che sono illimitati nel tempo). Per risolvere questo problema, ti consiglio di ospitare le tue pagine web su un server abilitato HTTPS ogni volta che è possibile.


12
@AndyDufresne Queste due richieste devono essere fatte tramite HTTPS (obbligatorio) poiché sono richieste al server OAuth che deve supportare solo HTTPS. È solo il server client / richiedente che non deve supportare HTTPS, quindi solo Auth Codepotenzialmente viene inviato in chiaro su HTTP. Ma Auth Codeè inutile senza l'ID cliente / Segreto. Fondamentalmente il punto del flusso del codice OAuth è che l'onere di avere un server abilitato SSL è sul provider OAuth (Google / Facebook ecc ...) e non sugli utenti delle API (tu, io).
Nicolas Garnier,

5
Ok, ora seguo che il codice di autenticazione potrebbe essere passato su un semplice HTTP e rischia di essere annusato. Rendendolo un codice usa e getta e accettando il client segreto per scambiarlo con un token di accesso, il server di autorizzazione potrebbe impedire l'attacco man-in-the-middle. Ma questo non vale anche per il token di accesso? Poiché l'utente dell'API potrebbe essere su un semplice HTTP, non ci sarà il rischio che il token di accesso venga sniffato dall'hacker? PS: apprezzo i tuoi sforzi per spiegare il concetto anche dopo che è passato un po 'di tempo da quando questo thread era attivo. Grazie !
Andy Dufresne,

8
no pb :) Le richieste all'API, ovvero quando il token di accesso viene inviato tramite il filo (per autorizzare la richiesta), vengono anch'esse fatte su HTTPS obbligatoriamente. In teoria il client non dovrebbe mai inviare il token di accesso over-the-wire in un semplice HTTP in qualsiasi momento.
Nicolas Garnier,

5
Il token di accesso in questo passaggio fa parte della risposta della richiesta HTTPS dal client al server delle risorse. Questa risposta è ancora crittografata.
Nicolas Garnier,

13
Fondamentalmente le richieste avviate dal client al server delle risorse vengono eseguite tramite HTTPS (poiché il server del proprietario della risorsa deve supportare il supporto HTTPS). Sono solo le richieste avviate da qualche altra parte al client che possono essere eseguite tramite HTTP (poiché il server client potrebbe non supportare HTTPS). Ad esempio, il reindirizzamento che si verifica durante il flusso di autorizzazione dopo che l'utente concede l'autorizzazione sulla pagina gant è un reindirizzamento avviato dal browser al server client e può essere eseguito in HTTP.
Nicolas Garnier,

8

Il flusso implicito rende l'intero flusso piuttosto semplice, ma anche meno sicuro .
Poiché l'applicazione client, che in genere JavaScript è in esecuzione all'interno di un browser, è meno affidabile, non vengono restituiti token di aggiornamento per l'accesso di lunga durata.
È necessario utilizzare questo flusso per applicazioni che richiedono un accesso temporaneo (alcune ore) ai dati dell'utente.
Restituire un token di accesso ai client JavaScript significa anche che l'applicazione basata su browser deve prestare particolare attenzione - pensa agli attacchi XSS che potrebbero perdere il token di accesso ad altri sistemi.

https://labs.hybris.com/2012/06/05/oauth2-the-implicit-flow-aka-as-the-client-side-flow


Mi aspetto che quando si ha una vulnerabilità XSS, anche il flusso del codice di autorizzazione non aiuta molto. Ma sono d'accordo sul fatto che il modo in cui il token di accesso viene passato a javascript nel flusso implicito è standardizzato (come frammento di hash) e se esiste una vulnerabilità XSS nel sito Web, quindi costruisce un attacco che legge il token di accesso dall'hash URL il frammento è abbastanza semplice. Con il flusso del codice di autorizzazione, d'altra parte, potrebbe essere possibile la falsificazione della richiesta tra siti.
Marcel

Inoltre, non si tratta solo di script tra siti. Qualsiasi libreria JavaScript in esecuzione nel tuo sito Web potrebbe tentare di rubare il token di accesso (ad esempio librerie CDN di terze parti o librerie open source utilizzate dal framework javascript).
Marcel

2
XSS non è un grosso problema ora quando abbiamo intestazioni della politica di sicurezza dei contenuti e hash SRI (Sub Resource Integrity).
Sergey Ponomarev,

4

Dalle specifiche OAuth :

4.2. Sovvenzione implicita

Il tipo di concessione implicita viene utilizzato per ottenere token di accesso (non supporta l'emissione di token di aggiornamento) ed è ottimizzato per i client pubblici noti per operare un URI di reindirizzamento particolare. Questi client sono in genere implementati in un browser utilizzando un linguaggio di scripting come JavaScript.

Poiché si tratta di un flusso basato sul reindirizzamento, il client deve essere in grado di interagire con l'agente utente del proprietario della risorsa (in genere un browser Web) e in grado di ricevere richieste in arrivo (tramite reindirizzamento) dal server di autorizzazione.

A differenza del tipo di concessione del codice di autorizzazione, in cui il client effettua richieste separate di autorizzazione e di token di accesso, il client riceve il token di accesso come risultato della richiesta di autorizzazione.

Il tipo di concessione implicita non include l'autenticazione client e si basa sulla presenza del proprietario della risorsa e sulla registrazione dell'URI di reindirizzamento. Poiché il token di accesso è codificato nell'URI di reindirizzamento, potrebbe essere esposto al proprietario della risorsa e ad altre applicazioni residenti sullo stesso dispositivo.

Quindi cosa possiamo considerare:

  1. Questo è per OAuth pubblico, cioè quando il client non ha bisogno di essere registrato e non ha i propri segreti. Ma quale server di autenticazione controlla l'URL di reindirizzamento e questo è effettivamente sufficiente per la sicurezza.

  2. Il token di accesso si trova nella barra degli indirizzi del browser, quindi l'utente può copiare l'URL e inviarlo a qualcun altro e inoltre viene registrato come utente, ovvero è qualcosa come la fissazione della sessione. Ma il browser effettua un reindirizzamento aggiuntivo con la sostituzione della cronologia per rimuovere il frammento di hash dall'URL. È anche possibile che un hacker rubi il token di accesso annusando un traffico HTTP ma questo può essere facilmente protetto da HTTPS. Alcune estensioni del browser dannose possono avere accesso agli URL dalla barra degli indirizzi, ma in definitiva questa è una brutta situazione come un cert HTTPS rotto. E anche il flusso di codice Auth non può aiutare qui etere. Quindi quello che posso vedere è che passare il token di accesso tramite il frammento di hash di url è assolutamente sicuro.

  3. La separazione del token di accesso effimero e del token di aggiornamento sono inutili quando si utilizza un HTTPS e, ad essere sinceri, non sono così utili nemmeno su HTTP non elaborato. Ma anche il fatto che il client tramite flusso implicito non possa ricevere il token di aggiornamento non ha senso.

Quindi penso che dovremmo introdurre un nuovo flusso di sovvenzione "implicito sicuro" che funziona rigorosamente su https, consente il token di aggiornamento (o dovremmo sbarazzarci di loro) ed è preferibile rispetto al flusso di sovvenzione Auth Cose


3

Per noi, i nostri clienti volevano essere in grado di autenticarsi con la nostra app sui loro telefoni una volta e non dover accedere di nuovo per settimane alla volta. Con il flusso di codice, ottieni un token di aggiornamento insieme al token di accesso. Il flusso implicito non ti dà un token di aggiornamento. Il token di accesso ha una scadenza relativamente breve, ma i token di aggiornamento possono avere una scadenza fino a 90 giorni. Ogni volta che il token di accesso scade, il codice client e del server può utilizzare quel token di aggiornamento per ottenere un nuovo token di accesso e un token di aggiornamento, tutti dietro le quinte, senza alcun intervento dell'utente. Un token di aggiornamento può essere utilizzato solo una volta. Non puoi farlo con Flusso implicito. Se stai utilizzando il flusso implicito e il tuo utente non interagisce con la tua app per più di un'ora, dovrà tornare di nuovo al suo ritorno. Questo non era accettabile nel nostro caso d'uso,

Funziona ed è sicuro perché i token di aggiornamento possono essere revocati. Se un cliente afferma di aver perso il telefono o il laptop o un hacker sul desktop, possiamo semplicemente revocare tutti i token di aggiornamento per quell'utente. Durante l'intero processo, nessuna informazione personale identificabile (PII) tocca mai il nostro codice, vale a dire la password dell'utente.

Il flusso di codice è fantastico, ma richiede più lavoro. MS non ha una libreria angolare per gestirla attualmente, quindi ho dovuto scriverne una. Se sei interessato, posso aiutarti.


2

La mia risposta è: non è possibile implementare il flusso implicito in modo semplice e sicuro con il server delle app web.

Il processo di autorizzazione dell'app Web comporta l'interazione dell'utente, quindi Authentication Server dovrebbe reindirizzare il browser dell'utente alla pagina di destinazione dell'app Web dopo l'autenticazione e il consenso dell'utente (non vedo alcun altro modo per restituire l'utente all'app Web dopo un'interazione con Server di autenticazione).

Quindi il token dovrebbe essere passato all'app Web usando l'URL di reindirizzamento, giusto?

Come ha spiegato @NicolasGarnier nella sua risposta e nei suoi commenti, non c'è modo di passare il token come frammento di URL: non raggiungerà il server delle app web.

E passare il token come parametro URL dell'URL di reindirizzamento sarebbe pericoloso anche in HTTPS: se la pagina di destinazione (lascia che sia "pagina di saluti") contiene risorse (immagini, script, ecc.), Queste risorse saranno ottenute dal browser attraverso la serie delle richieste HTTP (S) (ognuna delle quali ha Refererun'intestazione HTTP contenente l'URL esatto della "pagina dei saluti" inclusi i parametri URL). Questo è il modo in cui il token può perdere.

Quindi sembra che non ci sia modo di passare il token nell'URL di reindirizzamento. Ecco perché è necessaria una seconda chiamata (o dal server di autenticazione al client (ma a quale URL?) O dal client al server di autenticazione (la seconda chiamata nel flusso del codice di autorizzazione))

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.