La RFC 9700, pubblicata a gennaio 2025 come BCP 240, stabilisce quali misure di hardening di OAuth 2.0 sono MUST e quali solo SHOULD. Un redirect URI con wildcard dimenticato nella console di un identity provider è esattamente il tipo di configurazione che la RFC esclude, e un codice client pulito non basta a compensarla. La RFC aggiorna le RFC 6749, RFC 6750 e RFC 6819 e avverte che la sua adozione può compromettere l'interoperabilità con ecosistemi più datati. Raccomanda comunque di aggiornarsi non appena possibile.
I requisiti, in ordine di forza
| Impostazione | Livello | Posizione della RFC 9700 |
|---|---|---|
| Confronto dei redirect URI | MUST | Gli authorization server usano il confronto esatto tra stringhe |
| Open redirector | MUST NOT | Client e authorization server non devono esporli |
| Protezione CSRF | MUST | I client proteggono il redirection endpoint: PKCE, nonce o uno state monouso |
| Difesa dal mix-up, più authorization server | REQUIRED | Parametro iss o valore iss equivalente; redirection URI distinti come ripiego |
| PKCE, public client | MUST | Obbligatorio per l'authorization code grant |
| PKCE, confidential client | RECOMMENDED | I client OpenID Connect POSSONO usare nonce al suo posto, con precauzioni aggiuntive |
Applicazione di code_verifier | MUST | Verificato al token endpoint ogni volta che è stato inviato un code_challenge valido |
| Metodo di PKCE challenge | SHOULD | Uno che non esponga il verifier; al momento solo S256 |
Implicit grant (response_type=token) | SHOULD NOT | Usare code o un altro tipo che emetta i token al token endpoint |
| Access token sender-constrained | SHOULD | Mutual TLS o DPoP |
| Refresh token, public client | MUST | Sender-constrained oppure con rotazione |
Redirect URI: corrispondenza esatta e nessun open redirector
Quando l'authorization server confronta il redirect_uri di una richiesta con i valori registrati, deve usare il confronto esatto tra stringhe. L'unica eccezione è il numero di porta nei redirection URI localhost delle app native. Wildcard, corrispondenze per prefisso e registrazioni del tipo "qualsiasi percorso su questo host" violano tutte questa regola.
Anche l'elenco dei valori registrati è importante, perché ogni voce è una destinazione consentita per gli authorization code. Rimuova le voci obsolete, in particolare gli host che non controlla più, come un dominio di staging dismesso che qualcun altro potrebbe rilevare.
Gli open redirector sono l'altra metà del problema. Un endpoint che inoltra il browser a un URI arbitrario preso da un parametro di query può far trapelare authorization code e access token, e la RFC afferma che né i client né gli authorization server devono esporne uno. L'esempio di OWASP http://example.com/example.php?url=http://malicious.example.com mostra il problema: l'utente vede l'host attendibile e non nota il redirect.
La cheat sheet OWASP sui redirect non validati indica la soluzione. La scelta migliore è associare sul server un ID breve a una destinazione, invece di accettare un URL. Se deve accettarne uno, lo analizzi con un parser mantenuto attivamente e confronti schema, host canonico e porta effettiva con una allowlist esplicita. Rifiuti lo userinfo e non faccia mai corrispondenze su prefissi o suffissi grezzi.
PKCE su ogni client, obbligatorio su quelli pubblici
I public client devono usare PKCE. Per i confidential client è raccomandato, perché blocca anche il code injection e, come effetto collaterale, il CSRF. I confidential client OpenID Connect possono usare nonce e il corrispondente claim dell'ID Token al suo posto, ma solo con le precauzioni descritte nella Sezione 4.5.3.2. L'indicazione vale anche per le applicazioni web, benché PKCE sia stato progettato per le app native.
- Il valore della challenge deve cambiare a ogni transazione. Un valore costante vanifica lo scopo.
- Usi
S256. La RFC 9700 lo definisce al momento l'unico metodo che non espone il verifier nella richiesta di autorizzazione; altrimenti un attaccante in grado di leggere quella richiesta può rompere PKCE. La RFC 7636 aggiunge cheplainmitiga soltanto il caso di un attaccante che vede solo le risposte. - Il verifier è una stringa casuale di 43-128 caratteri tratti dall'insieme dei caratteri unreserved. La RFC 7636 raccomanda 32 ottetti casuali codificati in base64url, che producono 43 caratteri.
Il server deve inoltre impedire il downgrade: una richiesta al token endpoint con un code_verifier viene accettata solo se la richiesta di autorizzazione conteneva un code_challenge. Pubblicare code_challenge_methods_supported nei metadati del server permette ai client di rilevare il supporto a PKCE.
Implicit grant, CSRF e mix-up
I client non dovrebbero usare response_type=token né alcun response type che restituisca access token nella risposta di autorizzazione. La RFC 9700 li definisce vulnerabili a leakage e replay dei token e osserva che non esiste un metodo standardizzato per vincolare al mittente un token emesso in questo modo. Usi code, oppure un tipo che emetta i token al token endpoint, come code id_token.
La protezione dal CSRF sul redirection endpoint richiede PKCE (se il client ha verificato che il server lo supporta), il nonce nei flussi OpenID Connect, oppure un valore state monouso legato allo user agent. Se il Suo client dialoga con più di un authorization server, usi il parametro iss della RFC 9207 o un valore iss equivalente, come il claim dell'ID Token.
Token: sender-constrained dove possibile
Authorization server e resource server dovrebbero vincolare gli access token al mittente con mutual TLS (RFC 8705) o DPoP (RFC 9449), così che un token rubato sia inutile senza il segreto corrispondente. I refresh token dei public client devono essere sender-constrained o con rotazione, come descritto nella Sezione 4.14 della RFC.
Da dove iniziare
- Elenchi ogni redirect URI registrato per ogni client. Rimuova wildcard, percorsi parziali e host che non controlla più. Poi aggiunga un percorso o cambi un sottodominio in una richiesta di autorizzazione reale: il server dovrebbe rifiutarla.
- Cerchi parametri di redirect come
url,nextoreturnUrlsul client e sull'authorization server. Sostituisca gli URL liberi con una mappatura per ID lato server o con una allowlist su URL analizzati dal parser. - Cerchi
response_type=tokennel codice dei client e nelle impostazioni del server. Sposti quei client sull'authorization code flow con PKCE usandoS256. - Testi PKCE direttamente. Invii una richiesta di autorizzazione senza
code_challenge, poi riscatti il code con uncode_verifier. Poi riscatti un code protetto da PKCE senza il verifier. Entrambe le richieste dovrebbero fallire al token endpoint; se nella risposta c'è un token, il server non supera il test. - Testi
state: riproponga un valore già usato, poi ne invii uno proveniente da un'altra sessione del browser; il client deve rifiutarli entrambi. Se il Suo provider restituisceiss, lo manometta e verifichi che il client rifiuti la risposta. Ispezioni i claim dell'ID Token con il nostro strumento JWT e, se desidera una revisione esterna, un penetration test può coprire questi flussi. - Per i public client, scelga tra sender-constraining e rotazione. Se sceglie la rotazione, presenti due volte un refresh token già usato in un test e osservi come reagisce il server. Individui quel tentativo nei log dell'authorization server, poiché i nomi degli eventi variano a seconda del prodotto, e configuri un alert.
