Il Secure Sockets Layer (SSL)—ora tecnicamente noto come Transport Layer Security(TLS)—è un blocco comune per le comunicazioni crittografate tra client e server. È possibile che un’applicazione possa utilizzare SSL in modo errato in modo tale che entità dannose possano intercettare i dati di un’app sulla rete., Per aiutarti a garantire che ciò non accada alla tua app, questo articolo evidenzia le insidie comuni quando usi protocolli di rete sicuri e risolve alcune preoccupazioni più grandi sull’utilizzo dell’infrastruttura a chiave pubblica (PKI).
Dovresti anche leggere AndroidSecurity Overview e PermissionsOverview.
Concetti
In un tipico scenario di utilizzo SSL, un server è configurato con un certificato contenente una chiave pubblica e una chiave privata corrispondente., Come parte della stretta di mano tra un client SSL e un server, il server dimostra di avere la chiave privata firmando il suo certificato con crittografia a chiave pubblica.
Tuttavia, chiunque può generare il proprio certificato e la propria chiave privata, quindi una semplice handshakedoesn’t prova nulla sul server diverso dal fatto che il server conosce la chiave privata che corrisponde alla chiave pubblica del certificato. Un modo per risolvere questo problema è avere il clienthave un set di uno o più certificati di cui si fida. Se il certificato non è nel set, theserver non deve essere considerato attendibile.,
Ci sono diversi aspetti negativi di questo semplice approccio. I server dovrebbero essere in grado di passare a chiavi più forti nel tempo (“rotazione chiave”), che sostituisce la chiave pubblica nel certificato con una nuova. Sfortunatamente, ora l’app client deve essere aggiornata a causa di cosaè essenzialmente una modifica della configurazione del server. Ciò è particolarmente problematico se il servernon è sotto il controllo dello sviluppatore dell’app, ad esempio se si tratta di un servizio Web di terze parti. Thisapproach ha anche problemi se l’app deve parlare con server arbitrari come un browser Web o un’app di posta elettronica.,
Per risolvere questi aspetti negativi, i server sono in genere configurati con certificatida emittenti noti chiamati Autorità di certificazione (CA).La piattaforma host contiene generalmente un elenco di CAS ben noti che trusts.As di Android 4.2 (Jelly Bean), Android contiene attualmente oltre 100 CAS che vengono aggiornatiin ogni versione. Simile a un server, una CA ha un certificato e una chiave privata. Quando si emette un certificato per un server, la CA firma il certificato del server utilizzando la sua chiave privata. Theclient può quindi verificare che il server disponga di un certificato rilasciato da una CA nota alla piattaforma.,
Tuttavia, mentre si risolvono alcuni problemi, l’uso di CAs ne introduce un altro. Poiché la CA issuescertificates per molti server, hai ancora bisogno di un modo per assicurarti di parlare con il server che desideri. Per risolvere questo problema, il certificato rilasciato dalla CA identifica il servereither con un nome specifico come gmail.com o un set di host wildcarded come *.google.com.
Il seguente esempio renderà questi concetti un po ‘ più concreti., Nel frammento sottostante da una riga di comando, il comandoopenssl
s_client
esamina le informazioni sul certificato del server di Wikipedia. Itspecifica la porta 443 perché è l’impostazione predefinita per HTTPS. Il comando invia l’output di openssl s_client
a openssl x509
, che formatta le informazioni sui certificati secondo lo standard X. 509. In particolare, il comando richiede l’oggetto, che contiene le informazioni sul nome del server, e l’emittente, che identifica la CA.,
Si può vedere che il certificato è stato rilasciato per i server corrispondenti *.wikipedia.org dal RapidSSL CA.
Un esempio HTTPS
Supponendo che tu abbia un server web con un certificato rilasciato da una CA ben nota, puoi fare una richiesta sicura con codice simile a questo:
Sì, può davvero essere così semplice. Se si desidera personalizzare la richiesta HTTP, è possibile eseguire il cast toan HttpURLConnection
., La documentazione di Android per HttpURLConnection
contiene ulteriori esempi su come gestire le intestazioni di richiesta e risposta, pubblicare contenuti, gestire i cookie, utilizzare proxy, memorizzare nella cache le risposte e così via. Ma in termini di dettagli per la verifica dei certificati e dei nomi host, Androidframework si prende cura di te attraverso queste API.Questo è dove si vuole essere, se possibile. Detto questo, di seguito sono alcune altre considerazioni.,
Comune problemi di verifica i certificati del server
Supponiamo che invece di ricevere il contenuto di un getInputStream()
, viene generata un’eccezione:
Questo può accadere per diversi motivi, tra cui:
- La CA che ha emesso il certificato del server è stato unknown
- Il certificato del server non è stato firmato da una CA, ma era di firma automatica
- La configurazione del server è che manca un CA intermedio
Le seguenti sezioni spiegano come risolvere questi problemi, mantenendo yourconnection al server sicuro.,
Autorità di certificazione sconosciuta
In questo caso, si verificaSSLHandshakeException
perché si dispone di una CA non attendibile dal sistema. Potrebbe essere perché hai un certificato da una nuova CA che non è ancora attendibile da Android o la tua app è in esecuzione su una versione precedente senza la CA. Più spesso una CA è sconosciuta perché non è una CA pubblica, ma una privata emessa da un’organizzazione come un governo, una società o un istituto di istruzione per il proprio uso.
Fortunatamente, puoi insegnare a HttpsURLConnection
a fidarsi di un set specifico di CAS., La procedurapuò essere un po ‘ contorta, quindi di seguito è riportato un esempio che prende una CA specifica daan InputStream
, lo usa per creare un KeyStore
, che viene quindi utilizzato per creare e inizializzare unTrustManager
. Un TrustManager
è ciò che il sistema utilizza per convalidare i certificati dal serverand—creandone uno da unKeyStore
con uno o più CAS—quellisarà l’unico CAS di cui ci si fidiTrustManager
.,
Dato che il nuovo TrustManager
,l’esempio inizializza una nuova SSLContext
che: in questa SSLSocketFactory
è possibile utilizzare per modificare l’impostazione predefinitaSSLSocketFactory
daHttpsURLConnection
. In questo modo theconnection utilizzerà il tuo CAs per la convalida del certificato.
Ecco l’esempio di utilizzo completo di una CA organizzativa dell’Università di Washington:
Con unTrustManager
personalizzato che conosce la tua CA,il sistema è in grado di convalidare che il tuo certificato server provenga da un emittente attendibile.,
Attenzione:molti siti web descrivono una scarsa soluzione alternativa che consiste nell’installare un TrustManager
che non fa nulla. Se lo fai, potresti anche non crittografare la tua comunicazione, perché chiunque può attaccare i tuoi utenti in un hotspot Wi-Fi pubblico usando trucchi DNS per inviare il tuo users’traffic attraverso un proxy proprio che finge di essere il tuo server. L’attaccante può quindiregistrare password e altri dati personali., Funziona perché l’utente malintenzionato può generare acertificate e—senza un TrustManager
che in realtà valida che il certificato provenga da un trustedsource—la tua app potrebbe parlare con chiunque. Quindi non farlo, nemmeno temporaneamente. Puoi sempre rendere la tua app affidabile all’emittente del certificato del server, quindi fallo e basta.
Certificato server autofirmato
Il secondo caso diSSLHandshakeException
è dovuto a un certificato autofirmato, il che significa che il server si comporta come una propria CA.,Questo è simile a un’autorità di certificazione sconosciuta, quindi è possibile utilizzare lo stesso approccio dalla sezione precedente.
È possibile creare il proprio TrustManager
,questa volta affidandosi direttamente al certificato del server. Questo ha tutti gli aspetti discussi in precedenza di legare la tua app direttamente a un certificato, ma può essere fatto in modo sicuro. Tuttavia, dovresti fare attenzione a assicurarti che il tuo certificato autofirmato abbia una chiave areasonably forte. A partire dal 2012, una firma RSA a 2048 bit con un esponente di 65537 expiringyearly è accettabile., Quando si ruotano i tasti, è necessario verificare le raccomandazioni di anautorità (come NIST) su ciò che è accettabile.
Autorità di certificazione intermedia mancante
Il terzo caso diSSLHandshakeException
si verifica a causa di una CA intermedia mancante. La maggior parte dei publicCAs non firma direttamente i certificati del server. Invece, usano il loro certificato CA principale, indicato come CA radice, per firmare CAS intermedi. Lo fanno in modo che la CA radice può essere storedoffline per ridurre il rischio di compromesso., Tuttavia, i sistemi operativi come Android typicallytrust solo root CAs direttamente, che lascia un breve divario di fiducia tra il servercertificate—firmato dalla CA intermedia—e il certificate verifier,che conosce la CA root. Per risolverlo, il server non invia al client solo il suo certificato durante l’handshake SSL, ma una catena di certificati dalla CA del server attraverso eventuali intermedi necessari per raggiungere una CA root attendibile.
Per vedere come appare in pratica, ecco la posta.Google.,com certificatechain come visualizzato dal comandoopenssl
s_client
:
Questo mostra che il server invia un certificato per la posta.Google.commissionato dalla CA SGC Thawte, che è una CA intermedia, e un secondo certificatefor la CA SGC Thawte rilasciato da una CA Verisign, che è la CA primaria that’strusted da Android.
Tuttavia, non è raro configurare un server per non includere la CA necessaryintermediate., Ad esempio, ecco un server che può causare un errore nei browser Android eescezioni nelle app Android:
Ciò che è interessante notare qui è che visitare questo server nella maggior parte dei browser desktop non causa un errore come una CA completamente sconosciuta o un certificato server autofirmato. Questo perché la maggior parte dei browser desktop memorizza nella cache CA intermedi affidabili nel tempo. Una volta che il browser ha visitato e appreso di una CA intermedia da un sito, non sarà necessario includere la CA intermedia nella catena di certificati la prossima volta.,
Alcuni siti lo fanno intenzionalmente per server Web secondari utilizzati per servire le risorse. Per esempio, potrebbero avere la loro pagina HTML principale servita da un server con un certificatechain completo, ma avere server per risorse come immagini, CSS o JavaScript non includere theCA, presumibilmente per risparmiare larghezza di banda. Sfortunatamente, a volte questi server potrebbero fornireun servizio web che stai cercando di chiamare dalla tua app Android, che non è così indulgente.
Esistono due approcci per risolvere questo problema:
- Configurare il server per includere la CA intermedia nella catena server., La maggior parte delle CA fornisce documentazione su come farlo per tutti i server Web comuni. Questo è l’unico approccio se è necessario che il sito funzioni con i browser Android predefiniti almeno tramite Android 4.2.
- Oppure, tratta la CA intermedia come qualsiasi altra CA sconosciuta e crea un
TrustManager
per fidarti direttamente, come fatto nelle due sezioni precedenti.
Problemi comuni con la verifica del nome host
Come menzionato all’inizio di questo articolo,ci sono due parti fondamentali per verificare una connessione SSL., La prima verifica del certificato proviene da un’origine attendibile, che era al centro della sezione precedente. Il focus di questa sezione è la seconda parte: assicurarsi che il server su cui si sta parlando presenti il certificato corretto. Quando non lo fa, in genere vedrai un errorecome questo:
Una ragione per cui ciò può accadere è dovuta a un errore di configurazione del server. Il server isonfigured con un certificato che non ha un oggetto o campi nome alternativo soggetto che corrispondono al server che si sta tentando di raggiungere. È possibile utilizzare un certificatocon molti server diversi., Ad esempio, guardando il google.com certificato conopenssl
s_client -connect google.com:443 | openssl x509 -text
puoi vedere che un oggetto supporta *.google.com ma anche soggetti nomi alternativi per *.youtube.com,*. android.com, ed altri. L’errore si verifica solo quando il nome del server a cui ti stai connettendo non è elencato dal certificato come accettabile.
Sfortunatamente questo può accadere anche per un altro motivo: l’hosting virtuale. Quando si condivide aserver per più di un nome host con HTTP, il server Web può dire dalla richiesta HTTP / 1.1 quale nome host di destinazione il client sta cercando., Sfortunatamente questo è complicato CONHTTPS, perché il server deve sapere quale certificato restituire prima di vedere HTTPrequest. Per risolvere questo problema, le versioni più recenti di SSL, in particolare TLSv.1.0 e versioni successive, supporto Server Name Indication(SNI), che consente al client SSL di specificare intendedhostname sul server in modo che il certificato corretto possa essere restituito.
Fortunatamente, HttpsURLConnection
supportsSNI da Android 2.3. Un workaroundif è necessario supportare Android 2.,2 (e versioni precedenti) è impostare un host alternativevirtual su una porta univoca in modo che non sia ambiguo il certificato del server da restituire.
L’alternativa più drastica è sostituire HostnameVerifier
con uno che non usi il nome dell’host del tuo host virtuale, ma quello restituito dal server per impostazione predefinita.
Attenzione: sostituire HostnameVerifier
può essere molto pericoloso se l’altro host virtuale non è sotto il tuo controllo, perché anon-pathattacker potrebbe indirizzare il traffico verso un altro server a tua insaputa.,
Se siete ancora sicuri di voler sovrascrivere il nome host di verifica, qui c’è un esempio che sostituisce il verificatore per un singolo URLConnection
con uno che ancora si verifica che il nome è almeno previsto dall’app:
Ma ricordate, se vi trovate in sostituzione di hostname verifica, especiallydue di hosting virtuale, è ancora molto pericoloso se gli altri host virtuale isnot sotto il vostro controllo, e si dovrebbe trovare un’alternativa hosting arrangementthat per evitare questo problema.,
Avvertenze sull’utilizzo diretto di SSLSocket
Finora, gli esempi si sono concentrati su HTTPS utilizzandoHttpsURLConnection
.A volte le app devono utilizzare SSL separato da HTTP. Ad esempio, un’app di posta elettronica potrebbe utilizzare le varianti SSL di SMTP, POP3 o IMAP. In questi casi, l’app vorrebbe utilizzare SSLSocket
direttamente, più o meno allo stesso modo in cui HttpsURLConnection
fa internamente.
Le tecniche descritte per affrontare i problemi di verifica dei certificati si applicano anche a SSLSocket
.,Infatti, quando l’uso del TrustManager
, che è passato alHttpsURLConnection
è un SSLSocketFactory
.Quindi, se avete bisogno di utilizzare un custom TrustManager
con unSSLSocket
, followthe stessa procedura e l’uso che SSLSocketFactory
creare unSSLSocket
.
Attenzione: SSLSocket
non esegue la verifica del nome host. Spetta alla tua app eseguire la propria verifica del nome host, preferibilmente chiamando getDefaultHostnameVerifier()
con il nome host previsto., Furtherbeware che HostnameVerifier.verify()
non genera un’eccezione in caso di errore, ma restituisce un risultato booleano che è necessario controllare esplicitamente.
Ecco un esempio che mostra come puoi farlo. Mostra che quando si collega togmail.com porta 443 senza supporto SNI, riceverai un certificato formail.google.com. Questo è previsto in questo caso, quindi controlla per assicurarti che il certificato sia effettivamente per mail.google.com:
Denylisting
SSL si basa molto su CA per emettere certificati solo ai proprietari di server e domini correttamente verificati., In rari casi, le CA vengono ingannate o, nel caso di Comodo o DigiNotar,violate, con il risultato che i certificati per un nome host devono essere rilasciati a qualcuno diverso dal proprietario del server o del dominio.
Al fine di mitigare questo rischio, Android ha la possibilità di aggiungere determinati certificati o evenwhole CAS a un denylist. Mentre questo elenco è stato storicamente integrato nel sistema operativo, iniziandoin Android 4.2 questo elenco può essere aggiornato da remoto per affrontare futuri compromessi.,
Pinning
Un’app può proteggersi ulteriormente dai certificati emessi in modo fraudolento da atechnique noto come pinning. Questo utilizza fondamentalmente l’esempio fornito nel caso CA unknown above per limitare le CA attendibili di un’app a un piccolo set noto per essere utilizzato dai server dell’app. Thisprevents il compromesso di uno degli altri 100 + CAS nel sistema da risultante in una violazione del canale sicuro apps.
Certificati client
Questo articolo si è concentrato sull’utente di SSL per proteggere le comunicazioni con i server., SSL supporta anche la nozione di certificati client che consentono al server di convalidare l’identità di aclient. Mentre oltre lo scopo di questo articolo, le tecniche coinvolte sono simili a specifyinga personalizzata TrustManager
.
Nogotofail: Uno strumento di test di sicurezza del traffico di rete
Nogotofail è uno strumento ti dà un modo semplice per confermare che le applicazioni sono al sicuro contro le vulnerabilità note TLS / SSL e errori di configurazione. È uno strumento automatizzato, potente e scalabile per testare i problemi di sicurezza della rete su qualsiasi dispositivo il cui traffico di rete potrebbe essere fatto per attraversarlo.,
Nogotofail è utile per tre casi d’uso principali:
- Trovare bug e vulnerabilità.
- Verifica correzioni e guardare per regressioni.
- Capire quali applicazioni e dispositivi stanno generando quale traffico.
Nogotofail funziona per Android, iOS, Linux, Windows, Chrome OS, OSX, in realtà qualsiasi dispositivo che si utilizza per connettersi a Internet. C’è un client facile da usare per configurare le impostazioni e ricevere notifiche su Android e Linux, così come il motore di attacco stesso che può essere distribuito come router, server VPN o proxy.