Configurações de segurança de rede

O recurso de configurações de segurança de rede permite personalizar as definições de segurança de rede do seu app em um arquivo de configuração seguro e declarativo sem modificar o código do app. Essas configurações podem ser definidas para domínios específicos e para um determinado app. Os principais atributos do recurso são:

  • Âncoras de confiança personalizadas: personaliza quais autoridades certificadoras (AC) são confiáveis para as conexões seguras de um app. Por exemplo, confiar em certificados autoassinados particulares ou restringir o conjunto de ACs públicas em que o app confia.
  • Substituições somente de depuração: depura conexões seguras do app, sem adicionar riscos à base instalada.
  • Cancelamento do uso de tráfego de texto simples: protege apps contra o uso acidental de tráfego de texto simples.
  • Ativar a transparência de certificados:restrinja as conexões seguras de um app para usar certificados registrados de forma comprovada.
  • Fixação de certificados: restringe a conexão segura de um app a certificados específicos.

Adicionar um arquivo de configurações de segurança de rede

O recurso de configurações de segurança de rede usa um arquivo XML em que você especifica as configurações do seu app. Inclua uma entrada no manifesto do app que aponte para esse arquivo. Este exemplo de código de um manifesto demonstra como criar essa entrada:

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

Personalizar ACs confiáveis

Você pode querer que seu app confie em um conjunto personalizado de ACs em vez de no padrão da plataforma. Estes são os motivos mais comuns para isso:

  • Conectar-se a um host com uma AC personalizada, como uma AC autoassinada ou emitida internamente em uma empresa.
  • Limitar o conjunto de ACs para apenas aquelas em que você confia, em vez de todas as pré-instaladas.
  • Confiar em outras ACs não incluídas no sistema.

Por padrão, conexões seguras (que usam protocolos como TLS e HTTPS) de todos os apps confiam nas ACs pré-instaladas do sistema, e os apps destinados ao Android 6.0 (nível 23 da API) e versões anteriores também confiam no repositório de ACs adicionadas pelo usuário por padrão. Você pode personalizar as conexões do seu app usando base-config (para personalização em todo o app) ou domain-config (para personalização por domínio).

Configurar uma AC personalizada

É possível se conectar a um host que use um certificado SSL autoassinado ou a um host cujo certificado SSL seja emitido por uma AC não pública em que você confia, como a AC interna da sua empresa. O exemplo de código abaixo demonstra como configurar seu app para uma AC personalizada em 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>

Adicione o certificado da AC autoassinado ou não público em formato PEM ou DER em res/raw/my_ca.

Limitar o conjunto de ACs confiáveis

Se você não quiser que seu app confie em todas as ACs em que o sistema confia, especifique um conjunto reduzido de ACs confiáveis. Isso protege o app contra certificados fraudulentos emitidos por qualquer outra AC.

A configuração para limitar o conjunto de ACs confiáveis é semelhante a confiar em uma AC personalizada para um domínio específico, mas fornecendo várias ACs no recurso. O exemplo de código abaixo demonstra como limitar o conjunto de ACs confiáveis do seu app em 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>

Adicione as ACs confiáveis em formato PEM ou DER em res/raw/trusted_roots. Se você usar o formato PEM, o arquivo precisa conter apenas dados PEM, sem texto extra. Você também pode fornecer vários elementos <certificates> em vez de apenas um.

Confiar em outras ACs

Talvez você queira que seu app confie em outras ACs em que o sistema não confia. Por exemplo, se o sistema ainda não incluir a AC ou se ela não atender aos requisitos para inclusão no sistema Android. É possível especificar várias fontes de certificados para uma configuração em res/xml/network_security_config.xml usando um código como o trecho abaixo.

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

Configurar ACs para depuração

Ao depurar um app conectado por HTTPS, é recomendável que você se conecte a um servidor de desenvolvimento local que não tenha o certificado SSL do seu servidor de produção. Para fazer isso sem modificar o código do app, você pode usar debug-overrides para especificar ACs somente de depuração que sejam confiáveis somente quando o elemento android:debuggable for true. Normalmente, ambientes de desenvolvimento integrado e ferramentas de build definem essa flag automaticamente para builds que não são de lançamento.

Isso é mais seguro do que o código condicional normal, porque, como medida de segurança, os repositórios do app não aceitam apps marcados como depuráveis.

O trecho abaixo mostra como especificar ACs somente de depuração em 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>

Ativar a transparência dos certificados

A Transparência dos certificados (CT, RFC 9162) é um padrão da Internet desenvolvido para melhorar a segurança dos certificados digitais. Ele exige que as ACs enviem todos os certificados emitidos para um registro público que os registra, aumentando a transparência e a responsabilidade no processo de emissão de certificados.

Ao manter um registro verificável de todos os certificados, a CT dificulta muito a falsificação de certificados por usuários mal-intencionados ou a emissão deles por ACs por engano. Isso ajuda a proteger os usuários contra ataques "man-in-the-middle" e outras ameaças de segurança. Para mais informações, consulte a explicação em transparency.dev.

Por padrão, os certificados são aceitos, independentemente de estarem registrados em um registro de CT. Para garantir que o app se conecte apenas a destinos com certificados registrados em um registro de CT, você pode ativar o recurso globalmente ou por domínio.

Cancelar uso de tráfego de texto simples

Observação: a orientação desta seção se aplica apenas aos apps destinados ao Android 8.1 (nível 27 da API) ou versões anteriores. No Android 9 (nível 28 da API) e mais recentes, o suporte a texto não criptografado fica desativado por padrão.

Se você pretende que seu app se conecte a destinos usando apenas conexões seguras, desative o suporte a texto não criptografado (usando o protocolo HTTP não criptografado em vez de HTTPS) para esses destinos. Essa opção ajuda a evitar regressões acidentais em apps devido a mudanças nos URLs fornecidos por fontes externas, por exemplo, servidores de back-end. Consulte NetworkSecurityPolicy.isCleartextTrafficPermitted() para mais detalhes.

Por exemplo, você pode querer que seu app garanta que as conexões com secure.example.com sejam sempre realizadas por HTTPS para proteger o tráfego confidencial de redes hostis.

O exemplo abaixo mostra como desativar o texto não criptografado em 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>

Fixar certificados

Normalmente, um app confia em todas as ACs pré-instaladas. Se qualquer uma dessas ACs emitir um certificado fraudulento, um invasor no caminho poderá comprometer o app. Alguns apps optam por limitar o conjunto de certificados que aceitam restringindo o conjunto de ACs ou fixando certificados.

A fixação de certificados é realizada ao fornecer um conjunto de certificados pelo hash da chave pública (SubjectPublicKeyInfo do certificado X.509). Uma cadeia de certificados é válida somente se contiver pelo menos uma das chaves públicas fixadas.

Ao usar a fixação de certificados, é preciso sempre incluir uma chave de backup para que, se você precisar alternar para novas chaves ou mudar as ACs (ao fixar um certificado da AC ou um intermediário dela), a conectividade do seu app não seja afetada. Caso contrário, será necessário enviar uma atualização ao app para restaurar a conectividade.

Além disso, é possível definir um tempo de expiração para as fixações, para que depois disso elas não sejam mais realizadas. Isso ajuda a evitar problemas de conectividade em apps que não foram atualizados. No entanto, definir um prazo de validade para fixações pode permitir que invasores ignorem seus certificados fixados.

O exemplo abaixo mostra como fixar certificados em 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 de herança de configuração

Valores não definidos em uma configuração específica são herdados. Esse comportamento permite configurações mais complexas, mantendo o arquivo de configuração legível.

Por exemplo, valores não definidos em uma domain-config são obtidos pela domain-config mãe, se aninhados, ou, caso contrário, pela base-config. Valores não definidos no base-config usam os valores padrão da plataforma.

Por exemplo, considere um caso em que todas as conexões para subdomínios de example.com precisam usar um conjunto personalizado de ACs. Além disso, o tráfego de texto simples para esses domínios é permitido exceto ao se conectar com secure.example.com. Ao aninhar a configuração para secure.example.com dentro da configuração para example.com, o trust-anchors não precisa ser duplicado.

O trecho abaixo mostra como esse aninhamento ficaria em 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 do arquivo de configurações

O recurso de configurações de segurança de rede usa um formato do arquivo XML. A estrutura geral desse arquivo é mostrada no exemplo de código abaixo:

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

As seções abaixo descrevem a sintaxe e outros detalhes do formato do arquivo.

<network-security-config>

Pode conter:
0 ou 1 <base-config>
Qualquer quantidade de <domain-config>
0 ou 1 <debug-overrides>

<base-config>

Sintaxe:
<base-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</base-config>
Pode conter:
<trust-anchors> <certificateTransparency>
Descrição:
A configuração padrão usada por todas as conexões cujo destino não é coberto por uma domain-config.

Qualquer valor não definido usa os valores padrão da plataforma.

A configuração padrão para apps destinados ao Android 9 (nível 28 da API) e versões mais recentes é esta:

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

A configuração padrão para apps destinados ao Android 7.0 (nível 24 da API) até o Android 8.1 (nível 27 da API) é esta:

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

A configuração padrão para apps destinados ao Android 6.0 (nível 23 da API) e versões anteriores é esta:

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

<domain-config>

Sintaxe:
<domain-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</domain-config>
pode conter:
1 ou mais <domain>
0 ou 1 <certificateTransparency>
0 ou 1 <trust-anchors>
0 ou 1 <pin-set>
Qualquer número de <domain-config> aninhados
descrição:
A configuração usada para conexões com destinos específicos, conforme definida pelos elementos domain.

Observe que, se vários elementos domain-config cobrirem um destino, a configuração com a regra de domínio correspondente mais específica (mais longa) será usada.

<domain>

Sintaxe:
<domain includeSubdomains=["true" | "false"]>example.com</domain>
Atributos:
includeSubdomains
Se for "true", a regra de domínio corresponderá ao domínio e a todos os subdomínios, incluindo subdomínios de subdomínios. Caso contrário, a regra se aplicará apenas a correspondências exatas.

<certificateTransparency>

Sintaxe:
<certificateTransparency enabled=["true" | "false"]/>
descrição:
Se true, o app vai usar os registros de transparência de certificados para validar certificados. Quando um app usa o próprio certificado (ou o armazenamento de usuários), é provável que ele não seja público e, portanto, não seja verificável usando a transparência de certificados. Por default, a verificação é desativada nesses casos. Ainda é possível forçar a verificação usando <certificateTransparency enabled="true"/> na configuração do domínio. Para cada <domain-config>, a avaliação segue esta ordem:
  1. Se certificateTransparency estiver ativado, ative a verificação.
  2. Se algum <trust-anchors> for "user" ou inline (ou seja, "@raw/cert.pem"), desative a verificação.
  3. Caso contrário, use a configuração herdada.

<debug-overrides>

Sintaxe:
<debug-overrides>
    ...
</debug-overrides>
Pode conter:
0 ou 1 <trust-anchors>
Descrição:
Substituições a serem aplicadas quando android:debuggable for "true", o que normalmente ocorre em builds que não são de lançamento gerados por ambientes de desenvolvimento integrado e ferramentas de build. Âncoras de confiança especificadas em debug-overrides são adicionadas a todas as demais configurações e a fixação de certificados não é realizada quando a cadeia de certificados do servidor usa uma dessas âncoras de confiança somente de depuração. Se android:debuggable for "false", esta seção será ignorada por completo.

<trust-anchors>

Sintaxe:
<trust-anchors>
...
</trust-anchors>
Pode conter:
Qualquer quantidade de <certificates>
Descrição:
Conjunto de âncoras de confiança para conexões seguras.

<certificates>

Sintaxe:
<certificates src=["system" | "user" | "raw resource"]
              overridePins=["true" | "false"] />
Descrição:
Conjunto de certificados X.509 para elementos trust-anchors.
Atributos:
src
A fonte de certificados de AC. Os certificados podem ser destes tipos:
  • Um ID de recurso bruto que aponta para um arquivo que contém certificados X.509. Os certificados precisam ser codificados em formato DER ou PEM. No caso de certificados PEM, o arquivo não pode conter dados não PEM extras, como comentários.
  • "system" para certificados de AC pré-instalados do sistema
  • "user" para certificados de AC adicionados pelo usuário
overridePins

Especifica se as ACs dessa fonte ignoram a fixação de certificados. Se for "true", a fixação não será realizada em cadeias de certificados que são assinados por uma das ACs dessa fonte. Isso pode ser útil para depurar ACs ou para testar ataques de interceptação no tráfego seguro do seu app.

O padrão é "false" a não ser que seja especificado em um elemento debug-overrides. Nesse caso, o padrão será "true".

<pin-set>

Sintaxe:
<pin-set expiration="date">
...
</pin-set>
Pode conter:
Qualquer quantidade de <pin>
Descrição:
Um conjunto de fixações de chave pública. Para que uma conexão segura seja confiável, uma das chaves públicas na cadeia de confiança precisa estar presente no conjunto de fixações. Consulte <pin> para saber mais sobre o formato das fixações.
Atributos:
expiration
A data, no formato yyyy-MM-dd, na qual as fixações expiram e são desativadas. Se o atributo não for definido, as fixações não vão expirar.

A expiração ajuda a evitar problemas de conectividade em apps que não recebem atualizações para o conjunto de fixações, por exemplo, quando o usuário desativa as atualizações do app.

<pin>

Sintaxe:
<pin digest=["SHA-256"]>base64 encoded digest of X.509
    SubjectPublicKeyInfo (SPKI)</pin>
Atributos:
digest
O algoritmo de resumo usado para gerar a fixação. Atualmente, só há suporte para "SHA-256".

Outros recursos

Para mais informações sobre configurações de segurança de rede, consulte os recursos abaixo.

Codelabs