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à principali di questa funzionalità sono:

  • Ancore di attendibilità personalizzate: personalizza le autorità di certificazione (CA) considerate attendibili per le connessioni sicure di un'app. Ad esempio, laddove l'app consideri attendibili determinati certificati autofirmati o limiti l'insieme di CA pubbliche attendibili.
  • Sostituzione solo per il debug:esegui il debug in sicurezza delle connessioni sicure in un'app senza rischi aggiuntivi per la base installata.
  • Disattivazione del traffico in chiaro:protegge le app dall'utilizzo accidentale del traffico in chiaro (non criptato).
  • 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 determinati certificati.

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 file manifest della tua app per fare riferimento a questo file. Il seguente estratto di codice da un file 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 volere che la tua app consideri attendibile un insieme personalizzato di CA anziché quello predefinito della piattaforma. Ecco i motivi più comuni:

  • Connessione a un host con una CA personalizzata, ad esempio una CA autofirmata o emessa internamente all'interno di un'azienda.
  • Limitare l'insieme di CA solo a quelle che ritieni attendibili anziché a tutte quelle preinstallate.
  • Attribuire la massima attendibilità ad altre CA non incluse nel sistema.

Per impostazione predefinita, le connessioni sicure (che utilizzano protocolli come TLS e HTTPS) di tutte le app si basano sulle CA di sistema preinstallate e le app destinate ad Android 6.0 (livello API 23) e versioni precedenti si basano anche sul negozio CA aggiunto dall'utente per impostazione predefinita. Puoi personalizzare le connessioni della tua app utilizzando base-config (per la personalizzazione dell'intera app) o domain-config (per la personalizzazione per dominio).

Configura una CA personalizzata

Potresti volerti connettere a un host che utilizza un certificato SSL autofirmato o a un host il cui certificato SSL è stato emesso da un'autorità di certificazione non pubblica considerata attendibile, ad esempio l'autorità di certificazione 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>

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

Limita 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 attendibili. In questo modo, l'app è protetta da certificati fraudolenti emessi da altre CA.

La configurazione per limitare l'insieme di CA attendibili è simile alla convalida 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 delle 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.

Aggiungi altre CA attendibili

Potresti volere che la tua app consideri attendibili CA aggiuntive non considerate attendibili dal sistema, ad esempio se il sistema non include ancora l'autorità di certificazione o se quest'ultima non soddisfa i requisiti per l'inclusione nel sistema Android. Puoi specificare più origini dei certificati per una configurazione in res/xml/network_security_config.xml utilizzando un codice come l'estratto riportato di seguito.

<?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, ti consigliamo di collegarti a un server di sviluppo locale che non dispone del certificato SSL per il server di produzione. Per supportare questa funzionalità senza apportare modifiche al codice dell'app, puoi specificare CA solo per il debug, che sono attendibili solo quando android:debuggable è true, utilizzando debug-overrides. In genere, gli IDE e gli strumenti di compilazione impostano automaticamente questo flag per le build non di release.

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

L'estratto riportato di seguito mostra come specificare le CA solo per il 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

Certificate Transparency (CT, RFC 9162) è uno standard di 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à nella procedura di emissione dei certificati.

Mantenendo un record verificabile di tutti i certificati, la tecnologia CT rende notevolmente più difficile per gli 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 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.

Disattivare il traffico in testo non cifrato

Nota: le indicazioni riportate in questa sezione si applicano solo alle app che hanno come target Android 8.1 (livello API 27) o versioni precedenti. A partire da Android 9 (livello API 28), il supporto del testo non cifrato è disabilitato per impostazione predefinita.

Se vuoi che la tua app si connetta alle destinazioni utilizzando solo connessioni sicure, puoi disattivare il supporto del testo non cifrato (utilizzando il protocollo HTTP non criptato anziché HTTPS) per queste destinazioni. Questa opzione consente di evitare regressioni accidentali nelle app a causa di modifiche agli URL forniti da origini esterne come i server di backend. Per ulteriori dettagli, visita la pagina NetworkSecurityPolicy.isCleartextTrafficPermitted().

Ad esempio, potresti volere che la tua app garantisca che le connessioni a secure.example.com vengano sempre effettuate tramite HTTPS per proteggere il traffico sensibile dalle reti ostili.

L'estratto riportato di seguito mostra come disattivare il testo non cifrato in res/xml/network_security_config.xml:

<?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>

Bloccare i certificati

In genere, un'app considera attendibili tutte le CA preinstallate. Se una di queste CA emettesse un certificato fraudolento, l'app sarebbe a rischio di un attacco on-path. Alcune app scelgono di limitare l'insieme di certificati che accettano limitando l'insieme di CA che ritengono attendibili o tramite il pinning dei certificati.

Il pinning dei certificati viene eseguito fornendo un insieme di certificati tramite l'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 cambiare CA (quando esegui il pinning a un certificato CA o a un'intermedia di quella CA), la connettività della tua app non venga interessata. In caso contrario, devi implementare un aggiornamento dell'app per ripristinare la connettività.

Inoltre, è possibile impostare una data di scadenza per i pin dopo la quale non viene eseguito il pinning. In questo modo, puoi evitare problemi di connettività nelle app che non sono state aggiornate. Tuttavia, l'impostazione di una data di scadenza sui pin potrebbe consentire agli utenti malintenzionati di bypassare i certificati bloccati.

L'estratto riportato di seguito 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 leggibile il file di configurazione.

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

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

L'estratto riportato di seguito mostra l'aspetto di questo 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 file XML. La struttura generale del file è mostrata nel seguente esempio di codice:

<?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>

può contenere:
0 o 1 di <base-config>
Qualsiasi numero di <domain-config>
0 o 1 di <debug-overrides>

<base-config>

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

Per i valori non impostati vengono utilizzati 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) e 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>

syntax:
<domain-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</domain-config>
può 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 del dominio corrispondente più specifica (più lunga).

<dominio>

syntax:
<domain includeSubdomains=["true" | "false"]>example.com</domain>
attributes:
includeSubdomains
Se "true", questa regola del 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>

syntax:
<certificateTransparency enabled=["true" | "false"]/>
description:
Se true, l'app utilizzerà i log di Certificate Transparency per convalidare i certificati. Quando un'app utilizza il proprio certificato (o il proprio store utente), è probabile che il certificato non sia pubblico e quindi non sia verificabile utilizzando la trasparenza del certificato. 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, attiva la verifica.
  2. Se un <trust-anchors> è "user" o in linea (ovvero "@raw/cert.pem"), disattiva la verifica.
  3. In caso contrario, utilizza la configurazione ereditata.

<debug-overrides>

syntax:
<debug-overrides>
    ...
</debug-overrides>
può contenere:
0 o 1 <trust-anchors>
description:
Sostituzioni da applicare quando android:debuggable è "true", che in genere è il caso delle build non di release 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 ignorata completamente.

<trust-anchors>

syntax:
<trust-anchors>
...
</trust-anchors>
può contenere:
Qualsiasi numero di <certificates>
description:
Gruppo di ancore di attendibilità per connessioni sicure.

<certificates>

syntax:
<certificates src=["system" | "user" | "raw resource"]
              overridePins=["true" | "false"] />
description:
Set di certificati X.509 per gli elementi trust-anchors.
attributes:
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, come i commenti.
  • "system" per i certificati CA di sistema preinstallati
  • "user" per i certificati CA aggiunti dall'utente
overridePins

Specifica se le CA di questa origine ignorano il blocco dei certificati. Se "true", l'assegnazione non viene eseguita sulle catene di certificati che sono firmate da una delle CA di questa origine. Questo può essere utile per il debug delle CA o per testare gli 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>

syntax:
<pin-set expiration="date">
...
</pin-set>
può contenere:
Qualsiasi numero di <pin>
description:
Un insieme di pin di chiavi pubbliche. Affinché una connessione sicura sia attendibile, una delle chiavi pubbliche nella catena di attendibilità deve essere nell'insieme di pin. Consulta <pin> per il formato dei pin.
attributes:
expiration
La data, in formato yyyy-MM-dd, di scadenza dei pin, che comporta la disattivazione della funzionalità. Se l'attributo non è impostato, i PIN non scadono.

La scadenza aiuta a evitare problemi di connettività nelle app che non ricevono aggiornamenti al proprio insieme di PIN, ad esempio quando l'utente disattiva gli aggiornamenti delle app.

<pin>

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

Risorse aggiuntive

Per ulteriori informazioni sulla configurazione della sicurezza di rete, consulta le seguenti risorse.

Codelab