Configurazione della sicurezza di rete

La funzionalità Network Security Configuration ti consente di personalizzare le impostazioni di sicurezza di rete della tua app in un file di configurazione sicuro e dichiarativo senza modificare il codice dell'app. Queste impostazioni possono essere configurate per domini specifici e per un'app specifica. Le funzionalità chiave di questa funzionalità sono:

  • Trust anchor personalizzati: personalizza le autorità di certificazione (CA) considerate attendibili per le connessioni sicure di un'app. Ad esempio, considerare attendibili determinati certificati autofirmati o limitare l'insieme di CA pubbliche considerate attendibili dall'app.
  • Override solo per il debug:esegui il debug in sicurezza delle connessioni protette in un'app senza rischi aggiuntivi per la base installata.
  • Disattivazione del traffico in testo non crittografato:proteggi le app dall'utilizzo accidentale del traffico in testo non crittografato.
  • Attivazione di Certificate Transparency: limita le connessioni sicure di un'app all'utilizzo di certificati registrati in modo verificabile.
  • Pinning dei certificati:limita la connessione sicura di un'app a certificati particolari.

Aggiungere un file di configurazione della sicurezza di rete

La funzionalità Network Security Configuration utilizza un file XML in cui specifichi le impostazioni per la tua app. Devi includere una voce nel manifest della tua app per indirizzare a questo file. Il seguente estratto di codice da un manifest mostra come creare questa voce:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

Personalizzare le CA attendibili

Potresti voler che la tua app consideri attendibile un insieme personalizzato di CA anziché quello predefinito della piattaforma. I motivi più comuni sono:

  • Connessione a un host con una CA personalizzata, ad esempio una CA autofirmata o emessa internamente all'interno di un'azienda.
  • Limitando l'insieme di CA solo a quelle che ritieni attendibili anziché a tutte le CA preinstallate.
  • Considerare attendibili CA aggiuntive non incluse nel sistema.

Per impostazione predefinita, le connessioni sicure (che utilizzano protocolli come TLS e HTTPS) di tutte le app considerano attendibili le CA di sistema preinstallate e le app che hanno come target Android 6.0 (livello API 23) e versioni precedenti considerano attendibile anche l'archivio CA aggiunto dall'utente per impostazione predefinita. Puoi personalizzare le connessioni della tua app utilizzando base-config (per la personalizzazione a livello di app) o domain-config (per la personalizzazione per dominio).

Configura una CA personalizzata

Potresti voler connetterti a un host che utilizza un certificato SSL autofirmato o a un host il cui certificato SSL è emesso da una CA non pubblica di cui ti fidi, ad esempio la CA interna della tua azienda. Il seguente estratto di codice mostra come configurare l'app per una CA personalizzata in res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <trust-anchors>
            <certificates src="@raw/my_ca"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

Aggiungi il certificato CA autofirmato o non pubblico, in formato PEM o DER, a res/raw/my_ca.

Limitare l'insieme di CA attendibili

Se non vuoi che la tua app consideri attendibili tutte le CA attendibili dal sistema, puoi specificare un insieme ridotto di CA da considerare attendibili. In questo modo, l'app è protetta da certificati fraudolenti emessi da una delle altre CA.

La configurazione per limitare l'insieme di CA attendibili è simile all'attendibilità di una CA personalizzata per un dominio specifico, tranne per il fatto che nella risorsa vengono fornite più CA. Il seguente estratto di codice mostra come limitare l'insieme di CA attendibili della tua app in res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">secure.example.com</domain>
        <domain includeSubdomains="true">cdn.example.com</domain>
        <trust-anchors>
            <certificates src="@raw/trusted_roots"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

Aggiungi le CA attendibili, in formato PEM o DER, a res/raw/trusted_roots. Tieni presente che se utilizzi il formato PEM, il file deve contenere solo dati PEM e nessun testo aggiuntivo. Puoi anche fornire più elementi <certificates> anziché uno solo.

Considerare attendibili CA aggiuntive

Potresti voler che la tua app consideri attendibili CA aggiuntive che non sono considerate attendibili dal sistema, ad esempio se il sistema non include ancora la CA o se la CA non soddisfa i requisiti per l'inclusione nel sistema Android. Puoi specificare più origini certificati per una configurazione in res/xml/network_security_config.xml utilizzando un codice come il seguente estratto.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="@raw/extracas"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

Configura le CA per il debug

Quando esegui il debug di un'app che si connette tramite HTTPS, potresti voler connetterti a un server di sviluppo locale che non dispone del certificato SSL per il tuo server di produzione. Per supportare questa funzionalità senza modificare il codice dell'app, puoi specificare CA solo per il debug, che sono attendibili solo quando android:debuggable è true, utilizzando debug-overrides. Normalmente, gli IDE e gli strumenti di build impostano questo flag automaticamente per le build non di rilascio.

Questo è più sicuro del solito codice condizionale perché, come precauzione di sicurezza, gli store non accettano app contrassegnate come debuggabili.

Il seguente estratto mostra come specificare le CA solo di debug in res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <certificates src="@raw/debug_cas"/>
        </trust-anchors>
    </debug-overrides>
</network-security-config>

Attivare la trasparenza dei certificati

Nota: il supporto della trasparenza dei certificati è disponibile solo a partire da Android 16 (livello API 36).

Certificate Transparency (CT, RFC 6962) è uno standard internet progettato per migliorare la sicurezza dei certificati digitali. Richiede alle CA di inviare tutti i certificati emessi a un log pubblico che li registra, aumentando la trasparenza e la responsabilità nel processo di emissione dei certificati.

Mantenendo un registro verificabile di tutti i certificati, CT rende molto più difficile per i malintenzionati falsificare i certificati o per le CA emetterli per errore. In questo modo, è possibile proteggere gli utenti da attacchi man in the middle e altre minacce alla sicurezza. Per ulteriori informazioni, consulta la spiegazione su transparency.dev. Per saperne di più sulla conformità CT su Android, consulta le norme CT di Android.

Per impostazione predefinita, i certificati vengono accettati indipendentemente dal fatto che siano registrati in un log di CT. Per assicurarti che la tua app si connetta solo a destinazioni con certificati registrati in un log CT, puoi attivare la funzionalità a livello globale o per dominio.

Traffico in testo in chiaro

Gli sviluppatori possono attivare o disattivare il traffico cleartext (utilizzando il protocollo HTTP non criptato anziché HTTPS) per le loro applicazioni. Per maggiori dettagli, consulta NetworkSecurityPolicy.isCleartextTrafficPermitted().

Il comportamento predefinito del traffico cleartext dipende dal livello API:

Disattivare il traffico in testo non crittografato

Nota: le indicazioni in questa sezione si applicano solo alle app che hanno come target Android 8.1 (livello API 27) o versioni precedenti.

Se vuoi che la tua app si connetta alle destinazioni utilizzando solo connessioni sicure, puoi disattivare il supporto del traffico di testo non criptato verso queste destinazioni. Questa opzione consente di evitare regressioni accidentali nelle app a causa di modifiche agli URL forniti da fonti esterne come i server di backend.

Ad esempio, potresti voler che la tua app si assicuri che le connessioni a secure.example.com vengano sempre effettuate tramite HTTPS per proteggere il traffico sensibile da reti ostili.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">secure.example.com</domain>
    </domain-config>
</network-security-config>

Attivare il traffico in testo non crittografato

Nota: le indicazioni riportate in questa sezione si applicano solo alle app che hanno come target Android 9 (livello API 28) o versioni successive.

Se la tua app deve connettersi a destinazioni utilizzando il traffico in chiaro (HTTP), puoi attivare il supporto del traffico in chiaro per queste destinazioni.

Ad esempio, potresti voler consentire alla tua app di stabilire connessioni non sicure a insecure.example.com.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">insecure.example.com</domain>
    </domain-config>
</network-security-config>

Se la tua app deve attivare il traffico di testo non criptato verso qualsiasi dominio, imposta cleartextTrafficPermitted="true" in base-config. Tieni presente che questa configurazione non sicura deve essere evitata, se possibile.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
    </base-config>
</network-security-config>

Bloccare i certificati

Normalmente, un'app considera attendibili tutte le CA preinstallate. Se una di queste CA dovesse emettere un certificato fraudolento, l'app sarebbe a rischio di attacchi on-path. Alcune app scelgono di limitare l'insieme di certificati che accettano limitando l'insieme di CA di cui si fidano o tramite il certificate pinning.

Il pinning dei certificati viene eseguito fornendo un insieme di certificati tramite hash della chiave pubblica (SubjectPublicKeyInfo del certificato X.509). Una catena di certificati è valida solo se contiene almeno una delle chiavi pubbliche bloccate.

Tieni presente che, quando utilizzi il pinning dei certificati, devi sempre includere una chiave di backup in modo che, se sei costretto a passare a nuove chiavi o a modificare le CA (quando esegui il pinning a un certificato CA o a una CA intermedia), la connettività della tua app non venga interessata. In caso contrario, devi eseguire un aggiornamento dell'app per ripristinare la connettività.

Inoltre, è possibile impostare un periodo di scadenza per i pin dopo il quale il pinning non viene eseguito. In questo modo, si evitano problemi di connettività nelle app che non sono state aggiornate. Tuttavia, l'impostazione di un tempo di scadenza sui pin potrebbe consentire agli autori di attacchi di bypassare i certificati bloccati.

L'estratto seguente mostra come bloccare i certificati in res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <pin-set expiration="2018-01-01">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <!-- backup pin -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

Comportamento di ereditarietà della configurazione

I valori non impostati in una configurazione specifica vengono ereditati. Questo comportamento consente configurazioni più complesse mantenendo il file di configurazione leggibile.

Ad esempio, i valori non impostati in un domain-config vengono presi dall'elemento principale domain-config, se nidificato, o da base-config, in caso contrario. I valori non impostati in base-config utilizzano i valori predefiniti della piattaforma.

Ad esempio, considera un caso in cui tutte le connessioni ai sottodomini di example.com devono utilizzare un insieme personalizzato di CA. Inoltre, il traffico di testo non criptato verso questi domini è consentito tranne quando ci si connette a secure.example.com. Se nidifichi la configurazione per secure.example.com all'interno della configurazione per example.com, il trust-anchors non deve essere duplicato.

L'estratto riportato di seguito mostra l'aspetto di questa nidificazione in res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <trust-anchors>
            <certificates src="@raw/my_ca"/>
        </trust-anchors>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
        </domain-config>
    </domain-config>
</network-security-config>

Formato del file di configurazione

La funzionalità Network Security Configuration utilizza un formato di file XML. La struttura generale del file è mostrata nel seguente codice campione:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
    </base-config>

    <domain-config>
        <domain>android.com</domain>
        ...
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
        <pin-set>
            <pin digest="...">...</pin>
            ...
        </pin-set>
    </domain-config>
    ...
    <debug-overrides>
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
    </debug-overrides>
</network-security-config>

Le sezioni seguenti descrivono la sintassi e altri dettagli del formato del file.

<network-security-config>

possono contenere:
0 o 1 di <base-config>
Un numero qualsiasi di <domain-config>
0 o 1 di <debug-overrides>

<base-config>

sintassi:
<base-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</base-config>
possono contenere:
<trust-anchors> <certificateTransparency>
description:
La configurazione predefinita utilizzata da tutte le connessioni la cui destinazione non è coperta da un domain-config.

Tutti i valori non impostati utilizzano i valori predefiniti della piattaforma.

La configurazione predefinita per le app che hanno come target Android 9 (livello API 28) e versioni successive è la seguente:

<base-config cleartextTrafficPermitted="false">
    <trust-anchors>
        <certificates src="system" />
    </trust-anchors>
</base-config>

La configurazione predefinita per le app che hanno come target Android 7.0 (livello API 24) fino ad Android 8.1 (livello API 27) è la seguente:

<base-config cleartextTrafficPermitted="true">
    <trust-anchors>
        <certificates src="system" />
    </trust-anchors>
</base-config>

La configurazione predefinita per le app che hanno come target Android 6.0 (livello API 23) e versioni precedenti è la seguente:

<base-config cleartextTrafficPermitted="true">
    <trust-anchors>
        <certificates src="system" />
        <certificates src="user" />
    </trust-anchors>
</base-config>

<domain-config>

sintassi:
<domain-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</domain-config>
possono contenere:
1 o più <domain>
0 o 1 <certificateTransparency>
0 o 1 <trust-anchors>
0 o 1 <pin-set>
Qualsiasi numero di <domain-config>
nidificati
description:
Configurazione utilizzata per le connessioni a destinazioni specifiche, come definito dagli elementi domain.

Tieni presente che se più elementi domain-config coprono una destinazione, viene utilizzata la configurazione con la regola di corrispondenza del dominio più specifica (più lunga).

<dominio>

sintassi:
<domain includeSubdomains=["true" | "false"]>example.com</domain>
attributi:
includeSubdomains
Se "true", questa regola di dominio corrisponde al dominio e a tutti i sottodomini, inclusi i sottodomini dei sottodomini. In caso contrario, la regola si applica solo alle corrispondenze esatte.

<certificateTransparency>

sintassi:
<certificateTransparency enabled=["true" | "false"]/>
description:
Se true, l'app utilizzerà i log Certificate Transparency per convalidare i certificati. Quando un'app utilizza il proprio certificato (o l'archivio utente), è probabile che il certificato non sia pubblico e quindi non verificabile utilizzando la trasparenza dei certificati. Per impostazione predefinita, la verifica è disabilitata per questi casi. È comunque possibile forzare la verifica utilizzando <certificateTransparency enabled="true"/> nella configurazione del dominio. Per ogni <domain-config>, la valutazione segue questo ordine:
  1. Se certificateTransparency è attivato, abilita la verifica.
  2. Se un <trust-anchors> è "user" o in linea (ovvero "@raw/cert.pem"), disattiva la verifica.
  3. In caso contrario, fai affidamento alla configurazione ereditata.

<debug-overrides>

sintassi:
<debug-overrides>
    ...
</debug-overrides>
possono contenere:
0 o 1 <trust-anchors>
description:
Override da applicare quando android:debuggable è "true", il che si verifica normalmente per le build non di rilascio generate da IDE e strumenti di compilazione. I trust anchor specificati in debug-overrides vengono aggiunti a tutte le altre configurazioni e il pinning dei certificati non viene eseguito quando la catena di certificati del server utilizza uno di questi trust anchor solo per il debug. Se android:debuggable è "false", questa sezione viene completamente ignorata.

<trust-anchors>

sintassi:
<trust-anchors>
...
</trust-anchors>
possono contenere:
Qualsiasi numero di <certificates>
description:
Set di ancoraggi attendibili per connessioni sicure.

<certificates>

sintassi:
<certificates src=["system" | "user" | "raw resource"]
              overridePins=["true" | "false"] />
description:
Set di certificati X.509 per gli elementi trust-anchors.
attributi:
src
L'origine dei certificati CA. Ogni certificato può essere uno dei seguenti:
  • un ID risorsa non elaborato che rimanda a un file contenente certificati X.509. I certificati devono essere codificati in formato DER o PEM. Nel caso dei certificati PEM, il file non deve contenere dati non PEM aggiuntivi, ad esempio commenti.
  • "system" per i certificati CA di sistema preinstallati
  • "user" per i certificati CA aggiunti dagli utenti
overridePins

Specifica se le CA di questa origine ignorano il pinning dei certificati. Se "true", il pinning non viene eseguito sulle catene di certificati firmate da una delle CA di questa origine. Questo può essere utile per il debug delle CA o per testare attacchi man-in-the-middle sul traffico sicuro della tua app.

Il valore predefinito è "false", a meno che non sia specificato in un elemento debug-overrides, nel qual caso il valore predefinito è "true".

<pin-set>

sintassi:
<pin-set expiration="date">
...
</pin-set>
possono contenere:
Qualsiasi numero di <pin>
description:
Un insieme di pin della chiave pubblica. Affinché una connessione sicura sia attendibile, una delle chiavi pubbliche nella catena di attendibilità deve essere nel set di pin. Consulta <pin> per il formato dei pin.
attributi:
expiration
La data, nel formato yyyy-MM-dd, in cui scadono i pin, disattivando così il blocco. Se l'attributo non è impostato, i PIN non scadono.

La scadenza contribuisce a evitare problemi di connettività nelle app che non ricevono aggiornamenti al set di pin, ad esempio quando l'utente disattiva gli aggiornamenti delle app.

<pin>

sintassi:
<pin digest=["SHA-256"]>base64 encoded digest of X.509
    SubjectPublicKeyInfo (SPKI)</pin>
attributi:
digest
L'algoritmo di digest utilizzato per generare il pin. Al momento è supportato solo "SHA-256".