The Android Developer Challenge is back! Submit your idea before December 2.

Configuración de seguridad de la red

La función Configuración de seguridad de red les permite a las apps personalizar ajustes de seguridad de red mediante un archivo de configuración declarativo y seguro, sin necesidad de modificar el código de estas. Estos ajustes se pueden configurar para apps y dominios específicos. Las capacidades clave de esta función son las siguientes:

  • Anclajes de veracidad personalizados: Personaliza qué autoridades de certificación (CA) son de confianza para las conexiones de seguridad de una app. Por ejemplo, confiar en certificados autofirmados particulares o restringir el conjunto de CA públicas en las que confía la app.
  • Anulaciones exclusivas de depuración: Depura de forma segura conexiones de una app sin riesgos adicionales para la base instalada.
  • Inhabilitación de tráfico de Cleartext: Protege las apps contra el uso accidental del tráfico de Cleartext.
  • Fijación de certificados: Restringe la conexión segura de una app con certificados específicos.

Cómo agregar un archivo de configuración de seguridad de red

La función Configuración de seguridad de red usa un archivo XML en el que se especifican los ajustes de tu app. Debes incluir una entrada en el manifiesto de tu app que haga referencia a este archivo. El siguiente fragmento de código de un manifiesto demuestra cómo crear esta entrada:

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

Cómo personalizar las CA de confianza

Es posible que una app quiera confiar en un conjunto personalizado de CA en lugar de hacerlo según los ajustes predeterminados de la plataforma. Las razones más comunes son las siguientes:

  • Conectarse a un host con una autoridad de certificación personalizada, como una CA autofirmada o emitida a nivel interno en una empresa
  • Limitar el conjunto de CA para que incluya solo aquellas en las que confías, en lugar de todas las que estén preinstaladas
  • Otorgar confianza a CA adicionales que no estén incluidas en el sistema

De forma predeterminada, las conexiones seguras (con protocolos como TLS y HTTPS) de todas las apps confían en las CA preinstaladas del sistema, y las apps orientadas a Android 6.0 (nivel de API 23) y versiones anteriores también confían, de forma predeterminada, en las CA que agrega el usuario. Una app puede personalizar sus propias conexiones usando base-config (para la personalización de toda la app) o domain-config (para la personalización por dominio).

Cómo configurar una CA personalizada

Supongamos que quieres conectarte a tu host, que usa un certificado SSL autofirmado, o a un host cuyo certificado SSL está emitido por una CA privada en la que confías, como la de tu empresa.

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>
    

Agrega el certificado de CA autofirmado o privado, en formato PEM o DER, a res/raw/my_ca.

Cómo limitar el conjunto de CA de confianza

Una app que no quiera confiar en todas las CA que admita el sistema, de forma alternativa, especificar su propio conjunto reducido de CA en las que confiará. Esto brinda protección a la app ante certificados fraudulentos emitidos por cualquiera de las demás CA.

La configuración para limitar el conjunto de CA de confianza es similar a confiar en una CA personalizada para un dominio específico, con la excepción de que se proporcionan varias CA en el recurso.

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>
    

Agrega las CA de confianza, en formato PEM o DER, a res/raw/trusted_roots. Ten en cuenta que, si usas el formato PEM, en el archivo se deben incluir solo datos PEM, sin texto adicional. También puedes proporcionar varios elementos <certificates> en lugar de solo uno.

Cómo confiar en CA adicionales

Una app podría querer admitir CA adicionales en las que el sistema no confía, ya sea porque este aún no incluye la CA o porque la CA no cumple con los requisitos de inclusión del sistema Android. La app puede hacerlo especificando varias fuentes de certificado para una configuración.

res/xml/network_security_config.xml:

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

Cómo configurar las CA para depuración

Cuando depures una app que se conecte mediante HTTPS, recomendamos que te conectes a un servidor de desarrollo local que no tenga el certificado SSL de tu servidor de producción. Para hacerlo sin tener que modificar el código de tu app, usa debug-overrides a fin de especificar varias CA de solo depuración en las que se confíe únicamente cuando android:debuggable sea true. Generalmente, las herramientas de IDE y de compilación configuran este indicador automáticamente para las compilaciones no comerciales.

Esto es más seguro que el código condicional habitual ya que, como precaución, las tiendas de aplicaciones no aceptan apps que están marcadas como depurables.

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>
    

Cómo desactivar el tráfico de Cleartext

Nota: Las instrucciones que se brindan en esta sección solo se aplican a las apps orientadas a Android 8.1 (nivel de API 27) o versiones anteriores. A partir de Android 9 (nivel de API 28), la compatibilidad de Cleartext está inhabilitada de forma predeterminada.

Las aplicaciones que intenten conectarse a destinos usando solo conexiones seguras pueden desactivar la compatibilidad con Cleartext (usando el protocolo HTTP sin encriptar en lugar del protocolo HTTPS) para esos destinos. Esta opción ayuda a prevenir las regresiones accidentales en apps debido a cambios en direcciones URL generados por fuentes externas como servidores backend. Para obtener más detalles, consulta NetworkSecurityPolicy.isCleartextTrafficPermitted().

Por ejemplo, una app podría querer garantizar que todas las conexiones a secure.example.com se hagan siempre mediante HTTPS para proteger el tráfico sensible de redes hostiles.

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>
    

Cómo fijar certificados

Generalmente, una app confía en todas las CA preinstaladas. Si alguna de estas emitiera un certificado fraudulento, la app podría sufrir el ataque de un intermediario. Algunas apps eligen limitar el conjunto de certificados que aceptan, ya sea limitando el conjunto de CA en el que confían o fijando certificados.

La fijación de certificados se hace brindando un conjunto de certificados por hash de la clave pública (SubjectPublicKeyInfo del certificado X.509). De este modo, una cadena de certificados solo es válida si contiene al menos una de las claves públicas fijadas.

Ten en cuenta que si usas la fijación de certificados, deberás incluir una clave de respaldo para que, si te ves obligado a usar claves nuevas o a cambiar de CA (al fijar un certificado de CA o un intermediario de ella), no se vea afectada la conectividad de la app. De lo contrario, deberás actualizar la app para recuperar la conectividad.

Además, se puede configurar un período de vencimiento para las fijaciones, luego del cual se detendrán los procesos correspondientes. Esto ayuda a evitar los problemas de conectividad en apps que no se hayan actualizado. Sin embargo, configurar un período de vencimiento para las fijaciones puede habilitar la omisión de estas.

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>
    

Comportamiento de la configuración heredada

Se heredarán los valores que no se establezcan en una configuración específica. Este comportamiento permite configuraciones más complejas y, al mismo tiempo, conserva la legibilidad del archivo de configuración.

Si no se especifica un valor en una entrada determinada, se usará el de la entrada más general. Por ejemplo, los valores que no se establezcan en domain-config se obtendrán del elemento domain-config principal si están anidados, o de base-config si no lo están. Los valores no establecidos en base-config usan los valores predeterminados de la plataforma.

Por ejemplo, supongamos que todas las conexiones a subdominios de example.com deben usar un conjunto personalizado de CA. Además, se admite el tráfico de Cleartext a estos dominios excepto en el caso de las conexiones a secure.example.com. Si se anida la configuración de secure.example.com dentro de la de example.com, no será necesario duplicar trust-anchors.

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 archivo de configuración

La función Configuración de seguridad de red usa un formato de archivo XML. La estructura general del archivo se muestra en el siguiente ejemplo de código:

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

Las siguientes secciones describen la sintaxis y otros detalles del formato de archivo.

<network-security-config>

puede contener:
0 o 1 de <base-config>
Cualquier cantidad de <domain-config>
0 o 1 de <debug-overrides>

<base-config>

sintaxis:
    <base-config cleartextTrafficPermitted=["true" | "false"]>
        ...
    </base-config>
    
puede contener:
<trust-anchors>
descripción:
Corresponde a la configuración predeterminada que usan todas las conexiones cuyo destino no está cubierto por un elemento domain-config.

Los valores que no están configurados usan los valores predeterminados de la plataforma.

La configuración predeterminada de las apps orientadas a Android 9 (nivel de API 28) y versiones posteriores es la siguiente:

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

La configuración predeterminada de las apps orientadas a Android 7.0 (nivel de API 24) hasta Android 8.1 (nivel de API 27) es la siguiente:

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

La configuración predeterminada de las apps orientadas a Android 6.0 (nivel de API 23) y versiones anteriores es la siguiente:

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

<domain-config>

sintaxis:
<domain-config cleartextTrafficPermitted=["true" | "false"]>
        ...
    </domain-config>
Puede contener:
1 o más <domain>
0 o 1 <trust-anchors>
0 o 1 <pin-set>
Cualquier cantidad de elementos <domain-config> anidados
Descripción
Configuración usada para conexiones con destinos específicos, como los definidos por elementos de domain.

Ten en cuenta que, si varios elementos de domain-config cubren un destino, se usará la configuración con la regla de coincidencia de dominio más específica (más larga).

<domain>

sintaxis:
    <domain includeSubdomains=["true" | "false"]>example.com</domain>
    
Atributos:
includeSubdomains
Si es "true", esta regla de dominio coincidirá con el dominio y con todos los subdominios, incluidos los de otros subdominios. De lo contrario, solo se aplicará la regla a coincidencias exactas.
Descripción:

<debug-overrides>

sintaxis:
    <debug-overrides>
        ...
    </debug-overrides>
    
Puede contener:
0 o 1 <trust-anchors>
Descripción:
Corresponde a anulaciones que deben aplicarse cuando android:debuggable es "true", lo que generalmente se atribuye a las compilaciones no comerciales que se generan con herramientas de IDE y de compilación. Los anclajes de confianza especificados en debug-overrides se agregan a todas las demás configuraciones, y la fijación de certificados no se lleva a cabo cuando la cadena de certificados del servidor usa uno de estos anclajes de confianza de solo depuración. Si android:debuggable es "false", omite esta sección por completo.

<trust-anchors>

sintaxis:
    <trust-anchors>
    ...
    </trust-anchors>
    
Puede contener:
Cualquier cantidad de <certificates>
Descripción:
Conjunto de anclajes de confianza para conexiones seguras.

<certificates>

sintaxis:
<certificates src=["system" | "user" | "raw resource"]
                  overridePins=["true" | "false"] />
    
descripción:
Conjunto de certificados X.509 para elementos trust-anchors.
atributos:
src
Fuente de los certificados de CA. Cada certificado puede ser:
  • Un ID de recurso sin procesar que se dirija a un archivo que contenga certificados X.509. Los certificados deben estar codificados en formato DER o PEM. En el caso de certificados PEM, el archivo no debe contener datos adicionales que no sean PEM, como comentarios.
  • "system" para los certificados de CA preinstalados del sistema.
  • "user" para certificados de CA agregados por el usuario.
overridePins

Especifica si las CA de esta fuente omiten la fijación de certificados. Si es "true", no se realiza la fijación en las cadenas de certificados firmadas por una de las CA de esa fuente. Esto puede ser útil para depurar CA o para realizar pruebas de ataques de intermediarios en el tráfico seguro de tu app.

Es "false" de forma predeterminada, a menos que se especifique en un elemento debug-overrides, en cuyo caso, el valor predeterminado será "true".

<pin-set>

sintaxis:
    <pin-set expiration="date">
    ...
    </pin-set>
    
Puede contener:
Cualquier cantidad de <pin>
Descripción:
Es un conjunto de fijaciones de claves públicas. Para que una conexión segura sea de confianza, una de las claves públicas de la cadena de confianza debe estar en el conjunto de fijaciones. Consulta <pin> para obtener información sobre el formato de las fijaciones.
Atributos:
expiration
Fecha, en formato yyyy-MM-dd, en la que vencen las fijaciones, con lo que se inhabilita el proceso correspondiente. Si no se establece el atributo, las fijaciones no vencen.

El vencimiento ayuda a evitar problemas de conectividad en apps que no reciben actualizaciones para el conjunto de fijaciones; por ejemplo, cuando el usuario inhabilita las actualizaciones.

<pin>

sintaxis:
    <pin digest=["SHA-256"]>base64 encoded digest of X.509
        SubjectPublicKeyInfo (SPKI)</pin>
    
Atributos:
digest
Es el algoritmo implícito que se usa para generar la fijación. Actualmente, solo se admite "SHA-256".

Recursos adicionales

Para obtener más información sobre la configuración de seguridad de la red, consulta los siguientes recursos.

Codelabs