Perché è una cattiva idea usare semplicemente oauth2 per l'autenticazione?

23

TL; DR : quali sono le implicazioni sulla sicurezza dell'uso di oauth2 per l'autenticazione?

Sto costruendo un'app (sito A) che consente agli utenti di eseguire operazioni su un altro sito Web (sito B) tramite un'interfaccia più semplice.

Il sito B fornisce un'API che implementa OAuth2.0 per l'autorizzazione della mia app.

Pensavo che avrei potuto evitare di memorizzare le password e di avere gli utenti ancora-un altro account nella mia app portandola dietro l'autenticazione del sito B.

Ovviamente ho leggi la letteratura che colpisce il use di plain OAuth per l'autenticazione , ma non riesco a vedere come ciò sia negativo dal punto di vista della sicurezza.

Sembrano concentrarsi principalmente sulla praticità e (mancanza di) generalità della soluzione.

Ecco lo schema che avevo in mente:

  • Utente Sally carica il sito A e fa clic su "accesso"
  • Viene reindirizzata alla pagina di autorizzazione del sito B, dove si autentica o ha una sessione attiva
  • Se autorizza il sito A ad accedere al sito B per suo conto, viene reindirizzata al sito A con un codice di autorizzazione
  • Il sito A ottiene il codice di autorizzazione e lo scambia per un token di accesso (e un token di aggiornamento) tramite l'API del sito B.
  • Il sito A richiede al sito B l'ID utente di Sally e la registra con quell'ID
  • I token sono memorizzati in un database per essere utilizzati da un back-end, che esegue tutto il lavoro reale sul sito B.

Noterò che sto usando il cosiddetto "flusso lato server" qui. Inoltre, il authorization_code restituito nel terzo passaggio è un codice monouso di breve durata che è legato a A client_id e può essere utilizzato solo con il corrispondente client_secret .

Quando Sally accede da un altro dispositivo, il processo si ripete e i nuovi token vengono memorizzati.

L'unico problema che vedo è che all'utente verrà chiesto di autorizzare la mia app su ogni accesso anziché solo la prima volta, ma non è un problema al momento. Avrei anche chiesto un nuovo token quando ne ho effettivamente uno valido in negozio. Anche se un po 'poco pratico, questo non è un problema al momento (*) .

Quello che non riesco a vedere è come ciò sia negativo dal punto di vista della sicurezza.

Con un tale schema: quali sono i problemi di sicurezza per l'utente? E per l'app?

Mi sento come se mi mancasse qualcosa.

(*) Non avrò una grande base di utenti, solo alcuni utenti autorizzati. Quando (se) l'app cresce, ho intenzione di integrarlo in un sito più grande che utilizza un vero provider OpenID Connect. Voglio solo mantenerlo semplice, piccolo e concentrato durante questo test pilota

    
posta GnP 05.08.2016 - 17:31
fonte

3 risposte

23

Note: If you are looking for something like OAuth2, but for authentication you should
use OpenId Connect instead.

OAuth2 è pensato per consentire a un utente di autorizzare un'applicazione a caricare le risorse dell'utente da qualche fornitore di risorse. In altre parole: OAuth2 è un meccanismo per la delega di autorizzazione . Il protocollo non supporta l'autenticazione (anche se è comunemente usato impropriamente per quello).

Il buco della sicurezza è nel presupposto che fai nel 5 ° punto elenco.

Dici:

Site A asks site B for Sally's user_id and logs her in with that ID

Mentre in realtà dovrebbe leggere:

Site A asks site B for the user_id from the user-data that the access_token grants access to.

Figura1:flussoOAuthperclient(riservati)

Setuttovacomeprevisto,access_tokenè,ineffetti,dall'utentereindirizzatoaBperl'autenticazione.Ma:nonvièalcunagaranziachesiacosì.Infatti,qualsiasisitoWeb(dannoso)acuil'utentehaprecedentementeconcessoildirittodiaccedereaidatidell'utente(utilizzandoOAuth2conB),puòottenereunauthorization_codevalidodaBeinviarloate,alpunto3.

Inaltreparole,seeseguounsitoWebchechiedeagliutentiilpermessodiaccedereallelororisorseinButilizzandoOAuth2,possoimpersonaretuttiquegliutentiintuttiisitiWebcheutilizzanoinmodoimproprioOAuth2(conBcomeserverdiautorizzazioneOAuth2)perl'autenticazione.

Il"problema" con OAuth2 è che authorization_code è non generato per uno specifico client_id . Pertanto, se ricevi un authorization_code , non puoi essere certo che B abbia emesso la percentuale di co_de ricevuta da te o da un altro servizio. Che è ritenuto accettabile per autorizzazione ma è assolutamente inaccettabile per autenticazione .

Aggiorna :
Per quanto riguarda il tuo commento:

(and I restrict A to only accept one from users it previously redirected to B, but this is still unauthenticated)

Credo che tu stia qui aggiungendo un'ulteriore precauzione, che non è obbligatoria nel protocollo OAuth. In quanto tale, non può essere invocato.

    
risposta data 05.08.2016 - 20:27
fonte
8

Come spiegato da Jacco, un'implementazione ingenua dell'autenticazione su oauth2 ha diverse vulnerabilità, la più comune delle quali è CSRF .

Dato che esiste un protocollo di autenticazione perfettamente funzionante disponibile senza tutte queste trappole, non è una buona idea farlo da solo.

OTOH, c'è molto da imparare facendolo e comprendendo e risolvendo questi problemi.

TL; DR : non utilizzare oauth2 per l'autenticazione a meno che non lo si stia facendo per capire perché non si dovrebbe farlo. Utilizza OpenID Connect.

Modello di minaccia OAuth 2.0 e considerazioni sulla sicurezza

Prima di tutto, c'è un'analisi approfondita del modello di minaccia per oauth2 in RFC6819

Ci sono diversi possibili "flussi" in oauth2. Quello su cui mi sono concentrato per il mio progetto era il flusso authorization_code .

Autorizzazione "codice"

Ecco cosa RFC6819 ha da dire al riguardo:

An authorization "code" represents the intermediate result of a successful end-user authorization process and is used by the client to obtain access and refresh tokens. Authorization "codes" are sent to the client's redirect URI instead of tokens for two purposes:

  1. Browser-based flows expose protocol parameters to potential attackers via URI query parameters (HTTP referrer), the browser cache, or log file entries, and could be replayed. In order to reduce this threat, short-lived authorization "codes" are passed instead of tokens and exchanged for tokens over a more secure direct connection between the client and the authorization server.

  2. It is much simpler to authenticate clients during the direct request between the client and the authorization server than in the context of the indirect authorization request. The latter would require digital signatures.

Quindi i codici di autorizzazione sono più sicuri, yay!

Le vulnerabilità di

authorization_code flow sono analizzate in sezione 4.4.1 di RFC6819.

Questa sezione copre molto terreno. Mi concentrerò solo su alcune delle minacce.

CSRF

Dalla sezione 4.4.1.8:

An attacker could authorize an authorization "code" to their own protected resources on an authorization server. He then aborts the redirect flow back to the client on his device and tricks the victim into executing the redirect back to the client. The client receives the redirect, fetches the token(s) from the authorization server, and associates the victim's client session with the resources accessible using the token.

Impact: The user accesses resources on behalf of the attacker. [...] For example, the user may upload private items to an attacker's resources

Questo è anche trattato nella sezione 10.12 di RFC6749 :

The client MUST implement CSRF protection for its redirection URI. This is typically accomplished by requiring any request sent to the redirection URI endpoint to include a value that binds the request to the user-agent's authenticated state (e.g., a hash of the session cookie used to authenticate the user-agent). The client SHOULD utilize the "state" request parameter to deliver this value to the authorization server when making an authorization request.

Quindi nel tuo reindirizzamento al provider oauth2 devi semplicemente aggiungere un parametro state , che è semplicemente un token CSRF (dovrebbe essere non gestibile, memorizzato in un cookie sicuro, ecc.). Questo token verrà rispedito insieme a authorization_code quando il provider oauth2 reindirizza l'utente indietro.

Le contromisure per questo attacco devono essere implementate dal client e dal server di autorizzazione e possono anche essere applicate dal server di autorizzazione.

Il parametro state è anche trattato in questa domanda sec.SE .

Sostituzione codice (accesso OAuth)

Questo (trattato nella sezione 4.4.1.13 di RFC6819) è specificamente rivolto all'autenticazione sullo scenario oauth2.

Sostanzialmente un utente malintenzionato ottiene un authorization_code per l'utente tramite un sito dannoso (chiamiamolo sito C) e lo invia al sito legittimo (che chiamiamo ancora il sito A) che lo scambia per un token di accesso che è quindi utilizzato per affermare l'identità dell'utente tramite il server delle risorse. In questo modo l'utente malintenzionato accede come utente sul sito A.

Questo è quello menzionato da Jacco nella sua risposta.

Le contromisure per questo attacco devono essere implementate dal server di autorizzazione:

All clients must indicate their client ids with every request to exchange an authorization "code" for an access token. The authorization server must validate whether the particular authorization "code" has been issued to the particular client. If possible, the client shall be authenticated beforehand.

Altro

Che ci crediate o no, i precedenti attacchi e le loro contromisure coprono la maggior parte delle minacce all'autenticazione quando si utilizza il flusso del codice.

Esistono molte altre minacce e contromisure, molte delle quali dovrebbero essere sempre implementate:

Dalla sezione 4.4.1.3:

Handle-based tokens must use high entropy Authenticate the client; this adds another value that the attacker has to guess Bind the authorization "code" to the redirect URI; this adds another value that the attacker has to guess Use short expiry time for tokens

Questi dovrebbero essere tutti implementati dal server di autorizzazione.

Dalla sezione 4.1.1.4:

The authorization server should authenticate the client The authorization server should validate the client's redirect URI against the pre-registered redirect URI

Anche questi dovrebbero essere implementati dal server di autorizzazione.

Dalla sezione 4.4.1.5, 4.4.1.6 e altri:

the redirect URI of the client should point to an HTTPS protected endpoint

Questo dovrebbe essere implementato dal client e probabilmente applicato dal server di autorizzazione.

Quindi va bene usare oauth2 per l'accesso

No . Non farlo Utilizza OpenID Connect.

Ricordare le contromisure dalla sezione 4.4.1.13? Beh, ce n'era un altro che non ho citato:

Clients should use an appropriate protocol, such as OpenID (cf. [OPENID]) or SAML (cf. [OASIS.sstc-saml-bindings-1.1]) to implement user login. Both support audience restrictions on clients.

Ecco qua. Usa quello.

Se vuoi / devi ancora autenticarti con un provider oauth2, assicurati innanzitutto che il tuo provider applichi tutte le contromisure precedentemente citate.

Se lo fa, potresti riuscire a tirarlo fuori. Effettua test approfonditi e assumi un team di sicurezza per eseguire un'analisi completa della soluzione.

Inoltre, assicurati che tutte le funzioni del fornitore su cui fai affidamento per sicurezza siano documentate nell'API del tuo fornitore, altrimenti potrebbero essere rimosse senza preavviso e ti ritroverai con un prodotto Very Broken ™.

Nel mio caso:   - Sono stato abbastanza fortunato che il mio fornitore ha implementato tutte queste contromisure dalla loro parte.   - Non sto facendo affidamento su questo per l'autenticazione oltre un periodo iniziale di test dell'app (non è una funzione richiesta della mia app, solo un comodo pre-lancio di segnaposto)

Inoltre, ho imparato abbastanza su oauth2 durante questa implementazione per farne valere la pena.

Se vuoi saperne di più, leggi sia RFC6819 che RFC6749. Ho anche trovato molto utile questo sito .

    
risposta data 19.08.2016 - 05:08
fonte
1

Il buco della sicurezza nel tuo flusso:

She's redirected to site B's authorization page, where she either authenticates or has an active session

Se l'utente ha una sessione attiva sul sito B, e altri siti Web (sito C, D, ecc.) possono utilizzare il sistema OAuth del sito B per la loro autorizzazione, un sito dannoso (ad esempio sito x) potrebbe afferrare i token di accesso dal sito B e potenzialmente utilizzare la riproduzione di token per impersonare l'utente sul tuo sito ed eseguire azioni che non sono state autorizzate dall'utente. Rileggi l'esempio di Facebook nei tuoi link, spiega il problema.

La sfida con l'intero schema è che il tuo sito sarà sicuro quanto l'API OAuth del sito B. Come abbiamo appena dimostrato, la loro API non è sicura perché terze parti possono abusarne. In caso di abuso, la tua unica risorsa è fare ricorso al sito B per vietare il sito x. Personalmente non vorrei lasciare il destino della mia sicurezza nelle mani di un sito che non possedevo.

Un meccanismo più sicuro fornirebbe l'autenticazione del tuo sito contro l'elenco B dei client OAuth accettati, preferibilmente usando certificati client a chiave pubblica, e impedirebbe la riproduzione di token limitando l'uso di token al sito richiedente. Non puoi forzare il sito B ad adottare quel tipo di schema di accesso, quindi sei limitato a qualunque livello di sicurezza fornisca.

    
risposta data 05.08.2016 - 18:57
fonte

Leggi altre domande sui tag