Attacchi pratici ad OAuth 2.0 (e come difendersi)

Tempo di lettura: 14 minuti
Data pubblicazione: November 7, 2020

Introduzione

OAuth 2.0 è un protocollo che dà ad un client API un accesso limitato ai dati degli utenti su un server web. Ad esempio, viene utilizzato dalle API di GitHub, Google e Facebook. Esso si basa su scenari di autenticazione chiamati flussi, che permettono al proprietario della risorsa (l’utente) di condividere il contenuto protetto dal server della risorsa senza condividere le proprie credenziali. A tale scopo, un server OAuth 2.0 emette dei token di accesso che le applicazioni client possono utilizzare per accedere alle risorse protette per conto del proprietario della risorsa.

La specifica OAuth 2.0 definisce quattro ruoli:

  1. Il server di autorizzazione (Authorization Server), che è il server che emette il token di accesso.
  2. Il “proprietario della risorsa” (Resource Owner), normalmente l’utente finale dell’applicazione, che concede il permesso di accedere al server di risorse con un token di accesso.
  3. Il Client, è l’applicazione che richiede il token di accesso al Authorization Server e poi lo passa al Resource Server.
  4. Il Resource Server, che accetta il token di accesso e deve verificare che sia valido. In questo caso si tratta della vostra applicazione.

Il flusso di OAuth 2.0 è cosi definito:

  1. Il client richiede l’autorizzazione al proprietario della risorsa (solitamente l’utente).
  2. Se l’utente dà l’autorizzazione, il client passa la delega dell’autorizzazione al server di autorizzazione
  3. Se la delega è valida, il server di autorizzazione restituisce un token di accesso, eventualmente insieme ad un refresh e/o un ID token.
  4. Il client utilizza ora quel token di accesso per accedere al server delle risorse.
Flusso Schematico di Oauth 2.0
Flusso Schematico di Oauth 2.0

In questo articolo andremo ad approfondire alcuni degli attacchi principali al flusso tramite Authorization Code di OAuth 2.0 e alcune delle possibili mitigazioni.

Nota bene: le remediation effettuate di seguito sono state sviluppate solo come esempio e non devono essere seguite alla lettera o utilizzate in ambiente di produzione. Per risolvere possibili vulnerabilità consiglio di basarsi su RCF6819

Il seguente esempio è stato preso da Vulnerable-OAuth-2.0-Applications e modificato in base alle esigenze.

Esempio pratico di flusso

Il sito web di terze parti Photoprint consente agli utenti di stampare le immagini ospitate sul sito Gallery. L’applicazione Photoprint utilizza il Codice di Autorizzazione Grant.

Flusso d'esempio
Flusso d'esempio

L’interazione tra _Gallery _e _Photoprint _è la seguente:

  1. Photoprint permette di stampare foto ottenendole dal sito Gallery, dove l’utente ha la possibilità di caricare le proprie. Il sito per stampare permette questa interazione grazie al bottone Print Picture.
    Sito Photoprint
    Sito Photoprint
  2. Una volta cliccato, il client fa un redirect all’Authorization Server (Gallery in questo caso) ed effettua la seguente richiesta:
    Richiesta intercettata tramite Burp Proxy
    Richiesta intercettata tramite Burp Proxy
    Dove:
  • Response_type vale code, ossia che si sta utilizzando un authorization grant di tipo code.
  • Client_id è l’identificativo che rappresenta Photoprint
  • Redirect_url è l’indirizzo URL dove verrà redirezionato l’utente una volta conclusa l’operazione
  • Scope è il livello di accesso che il client ha bisogno (view_gallery permette ai client di vedere le immagini della galleria dell’utente)
  1. Il server chiede quindi all’utente il permesso di accedere alle sue immagini
    Photoprint chiede accesso alla galleria delle foto
    Photoprint chiede accesso alla galleria delle foto
  2. L’utente dà la conferma e viene effettuato un redirect verso Photoprint (come da parametro precedente) con l’authorization code
    Permesso accordato
    Permesso accordato
    Redirect con Authorization code
    Redirect con Authorization code
    5. Una volta che viene validato l’Authorization Code, viene effettuato un ulteriore redirect per selezionare le foto da stampare
    5. Una volta che viene validato l’Authorization Code, viene effettuato un ulteriore redirect per selezionare le foto da stampare
    Scelta delle foto da stampare
    Scelta delle foto da stampare
  3. Successivamente vengono inseriti i dati per l’invio delle stampe
    Inserimento dati per l'invio delle foto
    Inserimento dati per l'invio delle foto
  4. Infine l’ordine è concluso
    Ordine concluso
    Ordine concluso

Possibili attacchi nel flusso Autorizzativo in OAuth 2.0

Ricapitolando:

  1. Nella concessione del codice di autorizzazione, il Client scambia un codice autorizzativo con un token di accesso
  2. Per avviare questo flusso, il Resource Owner fa una richiesta al Client
  3. Il Client reindirizza quindi il Resource Owner al Server di Autorizzazione, passando un client_id, uno stato e redirect_uri.
  4. Dopo che il Resource Owner si autentica, il redirect_uri viene passato dal Server di Autorizzazione al Resource Owner insieme ad un codice.
  5. Il Resource Owner passa poi il codice al redirect_uri (che dovrebbe essere sul Client).
  6. Il Client può quindi utilizzare il codice, insieme al client_id e al client_secret per recuperare il codice di accesso. Il vantaggio di sicurezza di questo tipo di concessione include la possibilità di autenticare il Client tramite il client_secret, e il fatto che il token di accesso non viene mai esposto o trasmesso direttamente al Resource Owner, limitando le possibilità di compromissione. Di seguito i vettori di attacco più comuni contro un flusso di autorizzazione OAuth 2.0. Alcuni di questi problemi derivano da una mancanza di specificità nell’OAuth 2.0 originale, mentre altri rappresentano modelli comuni di cattiva programmazione (queste vulnerabilità possono essere introdotte sia dal Client che dal Server autorizzativo.)

Redirect_URI

Come da specifiche, dopo aver completato la sua interazione con il Resource Owner, il server di autorizzazione redirige l’utente verso il client. Il server di autorizzazione reindirizza poi all’endpoint precedentemente stabilito con il server di autorizzazione durante il processo di registrazione del client o quando si effettua la richiesta di autorizzazione. Il redirect_uri è probabilmente uno dei parametri più vulnerabili del flusso di OAuth 2.0. Alcuni casi possono essere:

  1. Nessuna validazione: ciò significa che qualsiasi url venga inserito, l’utente sarà redirezionato verso quella pagina
  2. Parziale validazione: alcune applicazioni implementano una parziale validazione ma potenzialmente bypassabile. Se il sito sicuro è example.com alcune modalità per bypassarla sono:
  3. testexample.com: l’applicazione verifica se l’url contiene example.com ma il sito è malevolo
  4. example.com.test.info: l’applicazione verifica solo il primo pattern, senza controllare in maniera corretta
  5. _example.com.info: _l’applicazione non valida tutto il dominio
  6. Path arbitrari permessi in redirect_url: in questo caso possono essere unite una serie di vulnerabilità, come Cross-Site scripting o open redirect
  7. Utilizzo di protocolli non sicuri: nel caso di una attacco Man-in-the-Middle potrebbe essere violata la confidenza delle informazioni

Code

Il parametro code contiene il codice di autorizzazione ricevuto dall’Authorization Server per il Resource Owner. Quest’ultimo lo presenta poi al Client, in modo che possa utilizzarlo per ottenere l’accesso. Le vulnerabilità più comuni possono essere in merito a:

  1. Validazione del periodo di validità: il token dovrebbe essere utilizzabile per un periodo minore di 10 minuti
  2. Riutilizzo: una volta che viene utilizzato dovrebbe essere scartato e non più utilizzabile
  3. Entropia: il token dovrebbe essere generato con una lunghezza >=128bit, altrimenti potrebbe essere suscettibile ad attacco di tipo bruteforce.

State

Il parametro State è stato introdotto per miticare attacchi di tipo Cross Site Request Forgery. Esso è consigliato e non obbligatorio nelle specifiche, anche se dovrebbe essere sempre utilizzato.

Il suo funzionamento è il seguente:

  1. Il client genera una stringa casuale e la inserisce come parametro alla richiesta all’authorization server. Questo valore è conosciuto anche dal Resource Owner
  2. L’authorization server effettua il redirect del Resource Owner verso il Client e include il parametro state
  3. Il client verifica la validità della richiesta effettuando un match dello state salvato precedentemente Quando si testa il parametro state si deve controllare:
  4. La presenza o meno dello stesso, essendo consigliato può non essere presente e l’applicativo vulnerabile ad attacchi CSRF
  5. Può non essere obbligatorio: anche se presente, se viene eliminato durante la richiesta manualmente e il server non da errore, significa che non c’è un controllo sulla presenza o meno e di conseguenza potrebbe essere vulnerabile ad attacchi.
  6. Bassa entropia: come per il token, se viene generato in maniera non sicura può essere soggetto ad attacchi di forza bruta

Client Secret

Il client_secret è un valore univoco per ogni resource server e permette di validare il code per gli access tokens.

Esso deve essere sempre mantenuto nascosto e non dev’essere visibile ad un normale utente. La sua divulgazione potrebbe permettere la violazione completa delle risorse del Resource Provider.

Esempi pratici di attacco e difesa

Mancata validazione dell’URL di redirect

Se l’authorization server non verifica che l’url di reindirizzamento appartiene al client, è suscettibile a due tipi di attacchi

Open Redirect con Phishing

Un attaccante potrebbe utilizzare l’endpoint di autorizzazione dell’utente finale e il reindirizzamento del parametro redirect_url per abusare dell’authorization server. Modificando il valore dell’url in un sito malevolo, un aggressore può lanciare con successo una truffa di phishing e rubare le credenziali dell’utente. Poiché il nome del server nel link modificato è identico al sito originale, i tentativi di phishing hanno un aspetto più affidabile.

Un attaccante potrebbe utilizzare la fiducia di un utente nell’authorization server per lanciare un attacco di tipo phishing.

Vulnerabilità Open Redirect
Vulnerabilità Open Redirect

L’applicativo _Gallery _non valida il parametro redirect_url, rendendolo di fatto vulnerabile ad attacchi di questo tipo.

Una volta cliccato il link, il sito Gallery chiede, come da flusso normale, di accede alla galleria delle foto.

Redirect_URL modificato
Redirect_URL modificato

L’utente ignaro viene poi redirezionato verso un finto sito dove vengono richieste le credenziali a causa di un errore generico.

Sito di phishing
Sito di phishing

Una volta inserite, l’attaccante ha a disposizione le stesse.

Credenziali rubate
Credenziali rubate

Per ovviare a questa situazione, bisogna legare l’authorization code all’ID cliente e all’URI di reindirizzamento e, se necessario, creare una whitelist di domini che verranno utilizzati per il reindirizzamento.

Codice potenzialmente corretto
Codice potenzialmente corretto
L'attacco non funziona più
L'attacco non funziona più

Open Redirect con sottrazione dell’authorization code

Non appena un utente accede con successo al server di autenticazione, il server rinvia all’applicazione con un codice di autorizzazione. Successivamente questo codice di autorizzazione viene utilizzato per ottenere il token di accesso nel backend.

Un aggressore potrebbe rubare l’access_token per ottenere il codice di autorizzazione e accedere al server di risorse.

Codice vulnerabile
Codice vulnerabile
Photoprint chiede l'accesso a gallery
Photoprint chiede l'accesso a gallery
L'attaccante ha ottenuto l'authorization code
L'attaccante ha ottenuto l'authorization code

Per ovviare a questa situazione, bisogna legare l’authorization code all’ID cliente e all’URI di reindirizzamento e, se necessario, creare una whitelist di domini che verranno utilizzati per il reindirizzamento.

  1. Prima di tutto un token non dovrebbe essere usato più di una volta, dev’essere rimosso dal database una volta utilizzato
  2. La scadenza del token deve essere convalidata, quindi bisogna impostare un limite di tempo entro il quale il token non può più essere utilizzato
  3. Si dovrebbe utilizzare una PKCE per lo scambio di token: la tecnica prevede che il client crei prima un segreto e poi lo usi di nuovo quando scambia il codice di autorizzazione con un token di accesso. In questo modo, se il codice viene intercettato, non sarà utile poiché la richiesta del token si basa sul segreto iniziale.

Mancato binding del client

Un client malintenzionato potrebbe fingere di essere un client valido e ottenere un’autorizzazione all’accesso al resource server. Un attaccante potrebbe quindi avere accesso ai dati privati degli utenti.

Client malevolo con authorization code valido
Client malevolo con authorization code valido
RIchiesta a gallery
RIchiesta a gallery
Gallery non valida ClientID ma solo l’authorization code
Gallery non valida ClientID ma solo l’authorization code
Accesso a dati sensibili
Accesso a dati sensibili

L’authorization server dovrebbe vincolare ogni codice di autorizzazione all’id del rispettivo client che ha avviato il processo di autorizzazione dell’utente finale. Questa misura è una contromisura contro:

  1. Replay di “codici” di autorizzazione con diverse credenziali del client, poiché un aggressore non può utilizzare un altro client_id per scambiare un codice di autorizzazione in un token
  2. Effettuare un attacco di tipo bruteforce agli authorization code
Codice non vulnerabile
Codice non vulnerabile
Gallery controlla se ClientID è associato all’authorization code
Gallery controlla se ClientID è associato all’authorization code
L’attacco precedente fallisce
L’attacco precedente fallisce

Authorization Code Debole

Un attaccante può tentare di indovinare i valori di “codice” di autorizzazione validi e inviare il valore del codice indovinato per ottenere un authorization token valido. Quando si creano segreti non destinati all’uso da parte di utenti umani, il server di autorizzazione dovrebbe includere un livello ragionevole di entropia al fine di mitigare il rischio di indovinare il token.

L'authorization code non viene generato in maniera sicura
L'authorization code non viene generato in maniera sicura
Attacco bruteforce
Attacco bruteforce
Attacco Bruteforce e identificazione di un token valido
Attacco Bruteforce e identificazione di un token valido

Il valore del token dovrebbe essere >=128 bit di lunghezza e costruito a partire da una sequenza numerica casuale o pseudo-casuale generata dal server di autorizzazione. La maggior parte dei framework OAuth 2.0 ormai lo implementano correttamente.

L'authorization code è più lungo di 8 caratteri e quasi impossibile da identificare
L'authorization code è più lungo di 8 caratteri e quasi impossibile da identificare

Ovviamente il token non viene generato in maniera cosi semplice, ma come precisato dev’essere lungo almeno 128 bit.

Mancanza del parametro State

Cross-site request forgery è una vulnerabilità che permette ad un aggressore di indurre gli utenti a compiere azioni che non intendono compiere. Essa permette all’aggressore di aggirare in parte la same origin polocy che è progettata per evitare che siti web diversi interferiscano tra loro.

In un attacco CSRF riuscito, l’aggressore induce l’utente vittima a compiere un’azione involontaria. Ad esempio, può trattarsi di cambiare l’indirizzo e-mail sul proprio conto, di cambiare la password o di effettuare un trasferimento di fondi. A seconda della natura dell’azione, l’aggressore potrebbe essere in grado di ottenere il pieno controllo sul conto dell’utente. Se l’utente compromesso ha un ruolo privilegiato all’interno dell’applicazione, l’aggressore potrebbe essere in grado di assumere il pieno controllo di tutti i dati e le funzionalità dell’applicazione.

Nell’esempio di seguito, un attaccante ha creato una richiesta nascosta dietro un semplice bottone, dove, dopo aver sottratto i dati bancari della vittima, ha inviato alla stessa un sito di phishing dove chiede di cliccare un bottone per stampare le foto

Bottone fasullo
Bottone fasullo
Richiesta all’interno dello stesso
Richiesta all’interno dello stesso
Una volta cliccato, l’utente compra le foto e le invia all’indirizzo dell’aggressore senza saperlo
Una volta cliccato, l’utente compra le foto e le invia all’indirizzo dell’aggressore senza saperlo
Le foto sono state comprate
Le foto sono state comprate

Prima di redirezionare l’utente, aggiungere il parametro state e validarlo durante la navigazione, in modo che nessuno possa replicare le richieste in maniera malintenzionata e inconsapevole per l’utente.

Conclusioni

Come abbiamo visto possono esserci, in aggiunta alle classiche vulnerabilità applicative, come SQL Injection, Cross Site Scripting, etc., anche una serie di problematiche in merito al semplice flusso di OAuth 2.0.

Nel RFC6819, denominata, OAuth 2.0 Threat Model and Security Considerations, sono inserite la maggior parte delle vulnerabilità che una errata implementazione del flusso può portare.

Oltre a quello, nel 2017 IETF (Internet Engineering Task Force) ha pubblicato una bozza denominata ‘OAuth 2.0 Security Best Current Practice’ nella quale vengono elencati i possibili attacchi a OAuth 2.0 e le mitigazioni agli stessi, in modo che chiunque potesse essere aggiornato e consapevole dei rischi associati ad errori di programmazione.

Riferimenti