Proteggere le comunicazioni su Android

Con tutte le recenti violazioni dei dati, la privacy è diventata un argomento importante. Quasi tutte le app comunicano attraverso la rete, quindi è importante considerare la sicurezza delle informazioni dell'utente. In questo post, imparerai le migliori pratiche correnti per proteggere le comunicazioni della tua app Android.

Usa HTTPS

Mentre sviluppi la tua app, è consigliabile limitare le richieste di rete a quelle essenziali. Per quelli essenziali, assicurati che siano realizzati su HTTPS anziché su HTTP. HTTPS è un protocollo che crittografa il traffico in modo che non possa essere facilmente intercettato dagli intercettatori. La cosa buona di Android è che migrare è semplice come cambiare l'URL da http a https

URL url = new URL ("https://example.com"); HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection (); httpsURLConnection.connect ();

Infatti, Android N e versioni successive possono applicare HTTPS utilizzando la configurazione di sicurezza di rete di Android.

In Android Studio, seleziona il app / res / xml directory per il tuo progetto. Crea il xml directory se non esiste già. Selezionalo e fai clic File> Nuovo file. Chiamalo network_security_config.xml. Il formato del file è il seguente:

   example.com  

Per indicare a Android di utilizzare questo file, aggiungi il nome del file al tag dell'applicazione nel file AndroidManifest.xml file:

Aggiorna i provider di crittografia

Il protocollo HTTPS è stato sfruttato più volte nel corso degli anni. Quando i ricercatori di sicurezza segnalano vulnerabilità, i difetti vengono spesso riparati. L'applicazione delle patch garantisce che le connessioni di rete della tua app utilizzino i protocolli standard del settore più aggiornati. Le versioni più recenti dei protocolli contengono meno punti deboli rispetto a quelli precedenti. 

Per aggiornare i provider di crittografia, è necessario includere i servizi di Google Play. Nel file del modulo di build.gradle, aggiungi la seguente riga alla sezione delle dipendenze:

implementazione 'com.google.android.gms: play-services-safetynet: 15.0.1'

L'API dei servizi SafetyNet ha molte più funzioni, tra cui l'API Navigazione sicura che controlla gli URL per vedere se sono stati contrassegnati come una minaccia nota e un'API reCAPTCHA per proteggere la tua app da spammer e altro traffico dannoso.

Dopo aver sincronizzato Gradle, puoi chiamare il ProviderInstaller'S installIfNeededAsync metodo:

public class MainActivity estende Activity implements ProviderInstaller.ProviderInstallListener @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); ProviderInstaller.installIfNeededAsync (questo, questo); 

Il onProviderInstalled () il metodo viene chiamato quando il provider viene aggiornato correttamente o è già aggiornato. Altrimenti, onProviderInstallFailed (int errorCode, Intent recoveryIntent) è chiamato. 

Certificato e blocco chiave pubblica

Quando si effettua una connessione HTTPS a un server, un certificato digitale viene presentato dal server e convalidato da Android per assicurarsi che la connessione sia sicura. Il certificato può essere firmato con un certificato da un'autorità di certificazione intermedia. Questo certificato utilizzato dall'autorità intermedia potrebbe a sua volta essere firmato da un'altra autorità intermedia e così via, che è affidabile fintanto che l'ultimo certificato è firmato da un'autorità di certificazione di root che è già considerata affidabile dal sistema operativo Android.

Se uno qualsiasi dei certificati nella catena di fiducia non è valido, la connessione non è sicura. Mentre questo è un buon sistema, non è infallibile. È possibile che un utente malintenzionato istruisca il sistema operativo Android ad accettare certificati personalizzati. I proxy di intercettazione possono disporre di un certificato attendibile e, se il dispositivo è controllato da un'azienda, la società potrebbe aver configurato il dispositivo in modo che accettasse il proprio certificato. Questi scenari consentono un attacco "man in the middle", che consente di decodificare e leggere il traffico HTTPS. 

Il blocco del certificato arriva in soccorso controllando il certificato del server presentato contro una copia del certificato previsto. Ciò impedisce che le connessioni vengano eseguite quando il certificato è diverso da quello previsto.

Per implementare il blocco su Android N e versioni successive, è necessario aggiungere un hash (chiamato pin) del certificato nel file network_security_config.xml file. Ecco un esempio di implementazione:

   duckduckgo.com  lFL47 + i9MZkLqDTjnbPTx2GZbGmRfvF3GkEh + J + 1F3g = w9MWhhnFZDSPWTFBjaoeGuClsrCs7Z70lG7YNlo8t + s =   

Per trovare i pin per un sito specifico, puoi andare su SSL Labs, accedere al sito e fare clic Sottoscrivi. Oppure, se stai sviluppando un'applicazione per un'azienda, puoi richiederla all'azienda.

Nota: se è necessario supportare dispositivi con una versione del sistema operativo precedente a Android N, è possibile utilizzare la libreria TrustKit. Utilizza il file di configurazione della sicurezza di rete esattamente nello stesso modo.

Sanificazione e validazione

Con tutte le protezioni finora, le tue connessioni dovrebbero essere abbastanza sicure. Anche così, non dimenticare la convalida della programmazione periodica. Il fidato cieco dei dati ricevuti dalla rete non è sicuro. Una buona pratica di programmazione è "design by contract", in cui gli input e gli output dei tuoi metodi soddisfano un contratto che definisce le specifiche aspettative dell'interfaccia. 

Ad esempio, se il tuo server si aspetta una stringa di 48 caratteri o meno, assicurati che l'interfaccia restituisca solo fino a 48 caratteri inclusi.

if (editText.getText (). toString (). length () <= 48)  ; //return something…  else  ; //return default or error 

Se ti aspetti solo numeri dal server, i tuoi input dovrebbero verificarlo. Mentre questo aiuta a prevenire errori innocenti, riduce anche la probabilità di attacchi di corruzione della memoria e di iniezione. Ciò è particolarmente vero quando i dati vengono passati a NDK o codice C / C ++ nativo di JNI.

Lo stesso vale per l'invio di dati al server. Non inviare dati ciecamente, specialmente se sono generati dagli utenti. Ad esempio, è buona norma limitare la lunghezza dell'input dell'utente, soprattutto se verrà eseguito da un server SQL o da qualsiasi tecnologia che eseguirà codice. 

Mentre la protezione di un server dagli attacchi va oltre lo scopo di questo articolo, come sviluppatore mobile, puoi fare la tua parte rimuovendo i caratteri per la lingua che il server sta utilizzando. In questo modo, l'input non è suscettibile agli attacchi di iniezione. Alcuni esempi sono la rimozione di virgolette, punti e virgola e barre quando non sono essenziali per l'input dell'utente:

string = string.replace ("\\", "") .replace (";", "") .replace ("\" "," ") .replace (" \ '"," ");

Se si conosce esattamente il formato previsto, è necessario verificarlo. Un buon esempio è la convalida dell'e-mail:

private final String emailRegexString = "^ [A-Za-z0-9 ._% + \\ -] + @ [A-Za-z0-9. \\ -] + \\. [A-Za-z]  2,4 $ "; private boolean isValidEmailString (String emailString) return emailString! = null && Pattern.compile (emailRegexString) .matcher (emailString) .matches (); 

Anche i file possono essere controllati. Se stai inviando una foto al tuo server, puoi verificare che sia una foto valida. I primi due byte e gli ultimi due byte sono sempre FF D8 e FF D9 per il formato JPEG.

booleano statico privato isValidJPEGAtPath (String pathString) genera IOException RandomAccessFile randomAccessFile = null; try randomAccessFile = new RandomAccessFile (pathString, "r"); long length = randomAccessFile.length (); se (lunghezza < 10L)  return false;  byte[] start = new byte[2]; randomAccessFile.readFully(start); randomAccessFile.seek(length - 2); byte[] end = new byte[2]; randomAccessFile.readFully(end); return start[0] == -1 && start[1] == -40 && end[0] == -1 && end[1] == -39;  finally  if (randomAccessFile != null)  randomAccessFile.close();   

Fai attenzione quando mostri un avviso di errore che mostra direttamente un messaggio dal server. I messaggi di errore potrebbero rivelare informazioni di debug o di sicurezza private. La soluzione è di fare in modo che il server invii un codice di errore che il client cerca per mostrare un messaggio predefinito.

Comunicazione con altre app

Mentre proteggi le comunicazioni da e verso il dispositivo, è importante proteggere anche IPC. Ci sono stati casi in cui gli sviluppatori hanno lasciato file condivisi o hanno implementato socket per lo scambio di informazioni sensibili. Questo non è sicuro. È meglio usare IntentoS. È possibile inviare dati utilizzando un Intento fornendo il nome del pacchetto in questo modo:

Intento intenzionale = nuovo Intento (); intent.setComponent (new ComponentName ("com.example.app", "com.example.app.TheActivity")); intent.putExtra ("UserInfo", "Esempio di stringa"); startActivity (intento);

Per trasmettere dati a più di un'app, devi applicare che solo le app firmate con la tua chiave di firma otterranno i dati. Altrimenti, le informazioni che invii possono essere lette da qualsiasi app che si registra per ricevere la trasmissione. Allo stesso modo, un'app dannosa può inviare una trasmissione alla tua app se ti sei registrato per ricevere la trasmissione. È possibile utilizzare un'autorizzazione per l'invio e la ricezione di trasmissioni dove firma è usato come il ProtectionLevel. Puoi definire un'autorizzazione personalizzata nel file manifest come questo:

 

Quindi puoi concedere l'autorizzazione in questo modo: 

Entrambe le app devono avere le autorizzazioni nel file manifest affinché funzioni. Per inviare la trasmissione:

Intento intenzionale = nuovo Intento (); intent.putExtra ("UserInfo", "Esempio di stringa"); intent.setAction ( "com.example.SOME_NOTIFICATION"); sendBroadcast (intent, "com.example.mypermission");

In alternativa, puoi usare setPackage (String) quando si invia una trasmissione per limitarla a un insieme di app corrispondenti al pacchetto specificato. Ambientazione Android: esportato a falso nel file manifest verranno escluse le trasmissioni ricevute dall'esterno dell'app.

Crittografia end-to-end

È importante comprendere i limiti di HTTPS per proteggere le comunicazioni di rete. Nella maggior parte delle implementazioni HTTPS, la crittografia viene terminata sul server. Ad esempio, la tua connessione al server di una società potrebbe essere su HTTPS, ma una volta che il traffico ha colpito il server, non è crittografato. Può quindi essere inoltrato ad altri server, stabilendo un'altra sessione HTTPS o inviandola non crittografata. La società è in grado di vedere le informazioni che sono state inviate e nella maggior parte dei casi è un requisito per le operazioni aziendali. Tuttavia, significa anche che l'azienda potrebbe trasferire le informazioni a terzi non crittografate.

C'è una tendenza recente chiamata "crittografia end-to-end" in cui solo i due dispositivi di comunicazione finali possono leggere il traffico. Un buon esempio è un'app di chat crittografata in cui due dispositivi mobili comunicano tra loro attraverso un server; solo il mittente e il destinatario possono leggere i messaggi l'uno dell'altro.

Un'analogia per aiutarti a capire la crittografia end-to-end è immaginare che tu voglia che qualcuno ti invii un messaggio che solo tu puoi leggere. Per fare ciò, fornisci loro una scatola con un lucchetto aperto su di essa (la chiave pubblica) mentre tieni la chiave del lucchetto (chiave privata). L'utente scrive un messaggio, lo inserisce nella casella, blocca il lucchetto e lo rispedisce all'utente. Solo tu puoi leggere il messaggio perché sei l'unico con la chiave per sbloccare il lucchetto.

Con la crittografia end-to-end, entrambi gli utenti si scambiano le proprie chiavi. Il server fornisce solo un servizio per la comunicazione, ma non può leggere il contenuto della comunicazione. Mentre i dettagli di implementazione vanno oltre lo scopo di questo articolo, è una tecnologia potente. Se vuoi saperne di più su questo approccio, un ottimo punto di partenza è il repository GitHub per il progetto Signal open source..

Conclusione

Con tutte le nuove leggi sulla privacy come GDPR, la sicurezza è sempre più importante. Spesso è un aspetto trascurato dello sviluppo di app per dispositivi mobili.

In questa esercitazione sono state illustrate le best practice sulla sicurezza, tra cui l'utilizzo di HTTPS, blocco dei certificati, sanitizzazione dei dati e crittografia end-to-end. Queste migliori pratiche dovrebbero servire come base per la sicurezza durante lo sviluppo della tua app mobile. Se avete domande, sentitevi liberi di lasciarle qui sotto, e mentre siete qui, date un'occhiata ad alcune delle mie altre esercitazioni sulla sicurezza delle app Android!