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:
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.
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 .