Qual è lo scopo del tipo di autorizzazione di concessione implicita in OAuth 2?


254

Non so se ho solo una sorta di punto cieco o cosa, ma ho letto le specifiche OAuth 2 molte volte e ho letto gli archivi della mailing list, e devo ancora trovare una buona spiegazione del perché la concessione implicita è stato sviluppato un flusso per ottenere i token di accesso. Rispetto alla concessione del codice di autorizzazione, sembra rinunciare all'autenticazione del client senza motivo molto convincente. Come viene "ottimizzato per i client implementato in un browser utilizzando un linguaggio di scripting" (per citare le specifiche)?

Entrambi i flussi iniziano allo stesso modo (fonte: http://tools.ietf.org/html/draft-ietf-oauth-v2-22 ):

  1. Il client avvia il flusso indirizzando l'agente utente del proprietario della risorsa all'endpoint di autorizzazione.
  2. Il server di autorizzazione autentica il proprietario della risorsa (tramite lo user-agent) e stabilisce se il proprietario della risorsa concede o rifiuta la richiesta di accesso del client.
  3. Supponendo che il proprietario della risorsa conceda l'accesso, il server delle autorizzazioni reindirizza l'agente utente al client utilizzando l'URI di reindirizzamento fornito in precedenza (nella richiesta o durante la registrazione del client).
    • L'URI di reindirizzamento include un codice di autorizzazione (flusso del codice di autorizzazione)
    • L'URI di reindirizzamento include il token di accesso nel frammento URI (flusso implicito)

Ecco dove si dividono i flussi. In entrambi i casi l'URI di reindirizzamento a questo punto è verso un endpoint ospitato dal client:

  • Nel flusso del codice di autorizzazione, quando l'agente utente raggiunge quell'endpoint con il codice di autorizzazione nell'URI, il codice in tale endpoint scambia il codice di autorizzazione con le credenziali del client per un token di accesso che può quindi utilizzare secondo necessità. Ad esempio, potrebbe scriverlo in una pagina Web a cui potrebbe accedere uno script sulla pagina.
  • Il flusso implicito salta del tutto questo passaggio di autenticazione client e carica semplicemente una pagina Web con script client. C'è un trucco carino qui con il frammento di URL che impedisce al token di accesso di essere passato troppo, ma il risultato finale è essenzialmente lo stesso: il sito ospitato dal client serve una pagina con qualche script in esso che può afferrare il token di accesso .

Da qui la mia domanda: cosa è stato guadagnato qui saltando il passaggio di autenticazione del client?



5
Il link nel commento precedente è morto. Eccone uno aggiornato
AndrewR,

3
Ho letto tutte le risposte qui, ma ancora non capisco come non sia sicuro che non sia necessario un segreto del client privato per ottenere un token di accesso. Diciamo che TrustedAppDeveloper rilascia TrustedPopularApp che consente agli utenti di concedergli le autorizzazioni (diciamo usando Twitter oauth) usando una concessione implicita. Se sono EvilAppDeveloper, cosa mi impedisce di creare un'app che passi TrustedPopularAppId come client_id in una richiesta di concessione implicita e quindi eseguire azioni (come lo spamming di un feed) per conto dell'utente, che ora sembrano provenire da TrustedPopularApp ?
adevine

Mi chiedo la stessa cosa di Adevine. Ma, molto probabilmente le app che richiedono una richiesta di concessione implicita, non hanno bisogno di più autenticazione, come tutte ottengono?
Mave,

13
@adevine Ciò che impedirebbe ad EvilApp nel tuo scenario di autenticarsi su Twitter come TrustedPopularApp è che non è in grado di ricevere i callback da Twitter, che sarebbero sempre inviati all'URI definito quando si registrava l'ID client
Ivan

Risposte:


196

Ecco i miei pensieri:

Lo scopo del codice di autenticazione + token nel flusso del codice di autorizzazione è che il token e il segreto del client non saranno mai esposti al proprietario della risorsa perché viaggiano da server a server.

D'altra parte, il flusso di concessione implicito è per i client che sono implementati interamente utilizzando javascript e sono in esecuzione nel browser del proprietario della risorsa. Non è necessario alcun codice lato server per utilizzare questo flusso. Quindi, se tutto accade nel browser del proprietario della risorsa, non ha più senso emettere il codice di autenticazione e il segreto del client, perché token e segreto del client verranno comunque condivisi con il proprietario della risorsa. L'inclusione del codice di autenticazione e del segreto client rende il flusso più complesso senza aggiungere ulteriore sicurezza reale.

Quindi la risposta su "cosa è stato guadagnato?" è "semplicità".


4
Grazie. Questo è un buon punto che nel flusso del codice di autorizzazione il proprietario della risorsa non ha mai bisogno di vedere il token di accesso, mentre nei client javascript questo è inevitabile. Il segreto del client potrebbe comunque essere mantenuto dai client javascript usando il flusso del codice di autorizzazione: dopo l'autenticazione e l'ottenimento di un token di accesso, il codice lato server passerebbe quindi il token al client javascript. Quello che vedo ora, tuttavia, è che il flusso di concessione implicito consente la distribuzione di SDK oauth javascript, come Facebook, liberando gli sviluppatori dalla necessità di scrivere completamente il proprio codice oauth.
Dan Taflin,

3
Vorrei aggiungere che il flusso del codice di autorizzazione consente ai client di archiviare i token e riutilizzarli. Nel flusso implicito, non hai sempre questa opzione e, come tale, il flusso implicito è una scelta pragmatica tra livello di sicurezza e convenienza.
PålOliver,

2
Questo risponde solo a metà e "cosa è stato perso"?
EralpB,

3
Non credo che questa sia una risposta esaustiva, il flusso implicito non ha lo scopo di trarre vantaggio dalla semplicità ma di compromettere i problemi di sicurezza con l'app sul lato client. Auth code, insieme a client_ide client_secretvengono utilizzati per identificare i client fidati che possono aggiornare i token per l'accesso a lungo termine e per "l'accesso offline" . Tuttavia, in un'app lato client, non è possibile registrare ciascun client, quindi il tipo di concessione implicita "semplificata" per l'accesso temporaneo alle informazioni dell'utente
Chen Xie,

1
Includere il segreto del client non solo rende il flusso più complesso, ma lo rende meno sicuro . Il segreto del client non è un segreto se deve essere elencato nel codice lato client e sarebbe quindi esposto a Internet. Se l'ID client viene utilizzato solo nei flussi impliciti, questo non è un problema. Ma se viene utilizzato anche altrove nella piattaforma per il token di aggiornamento o per le concessioni del codice di autorizzazione, avere il segreto corrispondente esposto è un grosso problema.
Ataraxia,

94

È lì per motivi di sicurezza, non per semplicità.

È necessario considerare la differenza tra l' agente utente e il client :

L'utente-agente è il software con cui l'utente ("proprietario della risorsa") comunica con altre parti del sistema (server di autenticazione e server delle risorse).

Il client è il software che desidera accedere alle risorse dell'utente sul server delle risorse.

Nel caso di user-agent e client disaccoppiati, la concessione del codice di autorizzazione ha senso. Ad esempio, l'utente utilizza un browser Web (user-agent) per accedere con il suo account Facebook su Kickstarter. In questo caso il client è uno dei server di Kickstarter, che gestisce gli accessi dell'utente. Questo server ottiene il token di accesso e il token di aggiornamento da Facebook. Pertanto, questo tipo di client considerato "sicuro", a causa dell'accesso limitato, i token possono essere salvati e Kickstarter può accedere alle risorse degli utenti e persino aggiornare i token di accesso senza l'interazione dell'utente.

Se l'utente-agente e il client sono accoppiati (ad es. Applicazione mobile nativa, applicazione javascript), è possibile applicare il flusso di lavoro di autorizzazione implicita . Si basa sulla presenza del proprietario della risorsa (per l'immissione delle credenziali) e non supporta i token di aggiornamento. Se questo client memorizza il token di accesso per un uso successivo, sarà un problema di sicurezza, poiché il token può essere facilmente estratto da altre applicazioni o utenti del client. L'assenza del token di aggiornamento è un ulteriore suggerimento, secondo cui questo metodo non è progettato per accedere alle risorse dell'utente in assenza dell'utente.


2
Vedo che il mio browser ha effettuato l'accesso al mio account google per mesi. Quindi Google utilizza il token di accesso sul browser o un token di accesso con un tempo di scadenza lungo? quale differenza nell'uso tra token di accesso con un lungo tempo di scadenza e token di accesso? qualsiasi altro client può catturare il token di accesso e utilizzarlo quando il proprietario della risorsa non è presente.
Mohammad Nikravan,

Suppongo che intendi la differenza tra token di aggiornamento e token di accesso con un lungo periodo di scadenza ? Il token di aggiornamento non deve essere salvato in scenari non sicuri, ma è possibile salvare il token di accesso (ad es. Nella memoria locale del browser). La sicurezza si ottiene mantenendo la durata del token di accesso il più bassa possibile, sebbene sia ancora comoda per gli utenti (ad es. È possibile disconnettersi automaticamente dopo x minuti di inattività). Se si utilizzano token di accesso di lunga durata, praticamente si rendono obsoleti i token di aggiornamento.
artkoenig,

Grazie per la tua spiegazione ma ho anche un'altra confusione. Non capisco perché abbiamo bisogno del flusso "Codice di autorizzazione". È possibile raggiungere lo stesso risultato sul server mediante flusso implicito (access_token) e un token di aggiornamento. Sembra che l'unica considerazione di sicurezza del flusso implicito sia che access_code dovrebbe avere una vita breve, quindi non può essere utilizzato da server a server. OK, ma il token di aggiornamento risolve questo problema. Perché dovremmo usare un flusso auth_code e richiedere access_token da quel token su un server per ottenere access_code mentre possiamo ottenere lo stesso risultato con refresh_token?
Mohammad Nikravan,

"il token può essere facilmente estratto da altre applicazioni" Come?
mvmn

@MohammadNikravan cercare la risposta in stackoverflow.com/q/13387698/355438
Lu55

60

La solita spiegazione è che la concessione implicita è più facile da implementare quando si utilizza un client JavaScript. Ma penso che questo sia il modo sbagliato di vederlo. Se stai utilizzando un client JavaScript che richiede risorse protette direttamente tramite XMLHttpRequest, la concessione implicita è la tua unica opzione, sebbene sia meno sicura. *

La concessione del codice di autorizzazione fornisce ulteriore sicurezza, ma funziona solo quando si dispone di un server Web che richiede le risorse protette. Poiché il server Web è in grado di memorizzare il token di accesso, si corre meno rischio che il token di accesso sia esposto a Internet e si può emettere un token che dura a lungo. E poiché il web server è attendibile, può ricevere un "token di aggiornamento", in modo che possa ottenere un nuovo token di accesso alla scadenza di quello vecchio.

Ma - e questo è un punto facile da perdere - la sicurezza del flusso del codice di autorizzazione funziona solo se il web server è protetto con una sessione, che viene stabilita con l'autenticazione dell'utente (login). Senza una sessione, un utente non attendibile potrebbe semplicemente effettuare richieste al server Web, utilizzando client_id, e sarebbe lo stesso se l'utente avesse il token di accesso. L'aggiunta di una sessione significa che solo un utente autenticato può accedere alle risorse protette. Client_id è solo l '"identità" della webapp JS, non l'autenticazione di detta webapp.

Significa anche che puoi terminare la sessione prima della scadenza del token OAuth. Non esiste un modo standard per invalidare un token di accesso. Ma se la sessione scade, il token di accesso è inutile, poiché nessuno lo sa tranne il web server. Se un utente non attendibile ottiene l'accesso alla chiave di sessione, sarà in grado di accedere alle risorse protette solo finché la sessione è valida.

Se non è presente un server Web, è necessario utilizzare la concessione implicita. Ciò significa che il token di accesso è esposto a Internet. Se un utente non attendibile accede ad esso, può utilizzarlo fino alla scadenza. Ciò significa che avranno accesso ad esso più a lungo rispetto a una concessione del codice di autorizzazione. Quindi potresti prendere in considerazione l'idea di far scadere prima il token ed evitare di dare accesso a risorse più sensibili.

* MODIFICA: Più recentemente, le persone consigliano di evitare l'uso della concessione implicita, anche su app Web senza server. Invece è possibile utilizzare la concessione del codice di autorizzazione configurata con un segreto vuoto, insieme a PKCE. La concessione del codice di autenticazione evita di archiviare il token di accesso nella cronologia del browser e PKCE evita di esporlo se qualcuno dirotta l'URL di reindirizzamento per rubare il codice di autenticazione. In questo caso è necessario che il server eviti di restituire un token di aggiornamento, poiché il client probabilmente non è in grado di memorizzarlo in modo sicuro. E dovrebbe emettere un token di accesso con le stesse limitazioni sopra menzionate.


21

Si riduce a: Se un utente esegue un'app Web (JavaScript) basata su browser o "pubblica", senza alcun componente lato server, l'utente si fida implicitamente dell'app (e del browser in cui viene eseguita, potenzialmente con altri browser app basate su ...).

Non esiste un server remoto di terze parti, solo il server delle risorse. Non vi è alcun vantaggio per un codice di autorizzazione, poiché non esiste nessun altro agente oltre al browser che agisce per conto dell'utente. Non ci sono vantaggi per le credenziali del cliente per lo stesso motivo. ( Qualsiasi client può tentare di utilizzare questo flusso.)

Le implicazioni per la sicurezza, tuttavia, sono significative. Da http://tools.ietf.org/html/rfc6749#section-10.3 :

Quando si utilizza il tipo di concessione implicita, il token di accesso viene trasmesso nel frammento URI, che può esporlo a parti non autorizzate.

Da http://tools.ietf.org/html/rfc6749#section-10.16 :

Il proprietario di una risorsa può delegare volontariamente l'accesso a una risorsa concedendo un token di accesso al client dannoso di un utente malintenzionato. Ciò può essere dovuto al phishing o ad altri pretesti ...


cosa intendi con "web" (JavaScript) app senza componente lato server? Come può esserci un'applicazione web senza server?
Zammy Pagina

2
@ZammyPage, questo sarebbe ciò che viene spesso chiamato Single Page App (SPA). L'intera app è gestita da una risorsa statica. Javascript nell'app accede quindi in modo dinamico a qualsiasi risorsa di cui abbia bisogno, a qualunque server di risorse a cui possa accedere. Non esiste un server che generi il contenuto del client: il javascript nel client modifica il DOM in base alle necessità per rappresentare le risorse a cui ha avuto accesso.
Elroy Flynn,

13

Non sono sicuro di aver capito correttamente la risposta e il commento di Dan. Mi sembra che la risposta abbia affermato che alcuni fatti sono corretti, ma indica esattamente ciò che l'OP ha chiesto. Se capisco correttamente, il principale vantaggio del flusso di concessione implicito è che un client come l'app JS (ad esempio l'estensione di Chrome) non deve esporre il segreto del client.

Dan Taflin ha detto:

... nel flusso del codice di autorizzazione il proprietario della risorsa non ha mai bisogno di vedere il token di accesso, mentre nei client javascript questo è inevitabile. Tuttavia, è possibile mantenere il segreto del client dai client JavaScript utilizzando il flusso del codice di autorizzazione.

Forse ti ho frainteso, ma il client (app JS in questo caso) deve passare le credenziali del client (chiave client e segreto) al server delle risorse nel flusso del codice di autorizzazione, giusto? Il segreto del client non può essere "mantenuto da JS".


6
Mi rendo conto che questa è una vecchia domanda, ma questa è una risposta migliore di quella accettata. Il motivo per cui esiste una concessione implicita è che un client javascript non può mantenere un segreto e quindi non può essere autenticato. Pertanto, il server delle autorizzazioni deve fare affidamento esclusivamente sulla registrazione dell'URI di reindirizzamento e sull'agente utente per la sicurezza. Passi i token di autorizzazione solo all'agente utente e solo a un uri di reindirizzamento specifico, teoricamente impedendo l'intercettazione (poiché un utente malintenzionato che non possiede il dominio dell'uri di reindirizzamento non può eseguire il codice nell'agente utente in tale uri).
raduna il

In effetti la risposta accettata mi ha confuso. Mi ha fatto pensare di aver frainteso quale sia il client_secret! Questa risposta e il commento sopra sono esatti.
Sarsaparilla,

9

Mentre la concessione implicita è stata progettata per supportare app che non potevano proteggere un segreto client, incluse le applicazioni JavaScript lato client, alcuni provider stanno implementando un'alternativa utilizzando il codice di autorizzazione senza un segreto client. L'OAuth 2.0 IETF RFC-6749 è stato pubblicato nel 2012 e le raccomandazioni attuali di alcune recenti discussioni sono del 2017.

La discussione 2017 sulla mailing list OAuth IETF è disponibile da questi implementatori:

Leggi di più qui:

Implicito era stato precedentemente raccomandato per i clienti senza un segreto, ma è stato sostituito usando la concessione del codice di autorizzazione senza alcun segreto.

...

In precedenza, si consigliava alle app basate su browser di utilizzare il flusso "Implicito", che restituisce immediatamente un token di accesso e non ha una fase di scambio di token. Nel momento in cui la specifica è stata originariamente scritta, le migliori pratiche del settore sono cambiate per raccomandare di utilizzare il flusso del codice di autorizzazione senza il segreto del client. Ciò offre maggiori opportunità per creare un flusso sicuro, ad esempio utilizzando il parametro state. Riferimenti: Redhat , Deutsche Telekom , Smart Health IT .

Il passaggio al codice di autenticazione senza il segreto del cliente dalla concessione implicita è menzionato anche per le app mobili qui:


Penso che tu voglia stare attento con questa raccomandazione. Questo è stato raccomandato nella guida per le app native, piuttosto che per le spa. Sfortunatamente non esiste una buona guida sulle ZPS, come documentato in molte discussioni online, forum e persino nella mailing list oauth-wg.
Tom,

La raccomandazione di passare al codice di autenticazione senza segreto dalla concessione implicita è una raccomandazione sia per le SPA che per le app mobili, ma il mio estratto sopra è specifico delle SPA. L'articolo a cui si fa riferimento utilizza un testo simile sia per le SPA che per le app mobili, ma con la lingua "app basate su browser" "app mobili e native" nel rispettivo testo. Anche i riferimenti per Redhat, DT, Smart Health IT sono specifici delle SPA e non sono inclusi nella nota per le app mobili. Ho aggiunto un link diretto alle ZPS nella risposta per facilitare la ricerca. Per favore pubblica alcuni link alle discussioni che menzioni.
Grokify

Una discussione oauth-wg abbastanza recente (2018) può essere trovata qui ietf.org/mail-archive/web/oauth/current/msg18020.html . RFC 8252 è per app native come suggerisce il titolo "OAuth 2.0 per app native". I riferimenti a Redhat, DT, Smart Health IT sono le risposte a una discussione sulla mailing list, non a un rfc, a una bozza di lavoro, ecc.
Tom,

3

oltre alle altre risposte, è anche importante rendersi conto che il profilo implicito consente un flusso solo sul canale anteriore rispetto al flusso del codice di autorizzazione che richiede una richiamata al server di autorizzazione; questo diventa evidente in OpenID Connect, che è un protocollo SSO basato su Auth 2.0 in cui il flusso implicito assomiglia al piuttosto popolare legame SAML POST e il flusso del codice di autorizzazione assomiglia al legame meno diffuso SAML Artifact


3

Nel flusso implicito se il browser dell'utente è corrotto (estensione / virus malvagi), la corruzione ottiene l'accesso alle risorse dell'utente e può fare le cose cattive.

Nel flusso di autenticazione la corruzione non può perché non conosce il segreto del client.


2

https://tools.ietf.org/html/rfc6749#page-8

Implicito

La concessione implicita è un flusso di codice di autorizzazione semplificato ottimizzato per i client implementati in un browser che utilizza un linguaggio di scripting come JavaScript. Nel flusso implicito, anziché emettere al client un codice di autorizzazione, al client viene emesso direttamente un token di accesso (come risultato dell'autorizzazione del proprietario della risorsa). Il tipo di concessione è implicito, poiché non vengono emesse credenziali intermedie (come un codice di autorizzazione) (e successivamente utilizzate per ottenere un token di accesso).

Quando si emette un token di accesso durante il flusso di concessione implicito, il
server di autorizzazione non autentica il client. In qualche
casi, l'identità del client può essere verificata tramite l'URI di reindirizzamento
utilizzato per consegnare il token di accesso al client. Il token di accesso può essere esposto al proprietario della risorsa o ad altre applicazioni con accesso all'agente utente del proprietario della risorsa.

Le sovvenzioni implicite migliorano la reattività e l'efficienza di alcuni
client (come un client implementato come applicazione nel browser),
poiché riducono il numero di round trip richiesti per ottenere un
token di accesso.


1

Penso che Will Cain abbia risposto a questo quando ha detto "Non ci sono vantaggi per le credenziali del client per lo stesso motivo. (Qualsiasi client può tentare di utilizzare questo flusso.)" Considera anche che il redirect_uri per il flusso implicito forse "localhost" - nessun callback viene creato dal server di autorizzazione per il flusso implicito. Poiché non è possibile fidarsi preventivamente del client, l'utente dovrebbe approvare il rilascio dei reclami dell'utente.


1

La concessione implicita consente di ottenere token dall'endpoint di autorizzazione con a GET. Ciò significa che il server di autorizzazione non deve supportare CORS.

Se questo non è un problema e non ci sono altri problemi relativi al server di autorizzazione non flessibili (ad esempio i token di aggiornamento non sono facoltativi, per qualche motivo), il flusso del codice di autorizzazione è quello preferito, anche per i clienti pubblici, in base alle recenti tendenze del settore e almeno a questa (attuale) istanza di un progetto ufficiale .

Storicamente c'erano altri motivi per implementare il flusso implicito, ma sembra che siano attualmente compensati dai vantaggi di sicurezza offerti dalla concessione del codice di autorizzazione, tra cui:

  • opzione per consegnare e utilizzare i token su un canale di ritorno per i clienti riservati
  • non esponendo token nella cronologia del browser per i client pubblici
  • interrompere un flusso non autorizzato prima che vengano emessi token - con PKCE , per "tutti i tipi di client OAuth"

0

Ho appena affrontato un articolo su OAuth 2.0. L'autore afferma che il motivo dietro il flusso implicito è che le app JS erano molto limitate nelle richieste lì:

se ti chiedi perché il tipo implicito sia stato incluso in OAuth 2.0, la spiegazione è semplice: stessa politica di origine. All'epoca, alle applicazioni frontend non era consentito inviare richieste a host diversi per ottenere il token di accesso utilizzando il codice. Oggi abbiamo CORS (Cross-Origin Resource Sharing).

https://medium.com/securing/what-is-going-on-with-oauth-2-0-and-why-you-should-not-use-it-for-authentication-5f47597b2611

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.