Configuración de seguridad de la red

La función Configuración de seguridad de red te permite personalizar los parámetros de configuración de seguridad de red de tu app con un archivo de configuración declarativo y seguro, sin modificar el código de la app. Estas opciones se pueden configurar para dominios específicos y para una app específica. Las funciones clave son las siguientes:

  • Anclas de confianza personalizadas: Personaliza qué autoridades certificadoras (AC) son de confianza para las conexiones de seguridad de una app. Por ejemplo, confiar en certificados autofirmados particulares o restringir el conjunto de AC 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 texto simple: Protege las apps contra el uso accidental del tráfico de texto simple (sin encriptar).
  • 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 la red usa un archivo XML en el que se especifican los parámetros para tu app. Debes incluir una entrada en el manifiesto de tu app que haga referencia a este archivo. En el siguiente fragmento de código de un manifiesto, se muestra 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 AC de confianza

Es posible que desees que tu app confíe en un conjunto personalizado de AC en lugar de los valores predeterminados de la plataforma. Las razones más comunes son las siguientes:

  • Conectarse a un host con una autoridad certificadora personalizada, como una AC autofirmada o emitida a nivel interno en una empresa
  • Limitar el conjunto de AC para que incluya solo aquellas en las que confías, en lugar de todas las que estén preinstaladas
  • Otorgar confianza a AC 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 AC 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 AC que agrega el usuario. Puedes personalizar las conexiones de tu app con base-config (para la personalización de toda la app) o domain-config (para la personalización por dominio).

Cómo configurar una AC personalizada

Es posible que desees conectarte a un host que usa un certificado SSL autofirmado o a un host cuyo certificado SSL está emitido por una AC privada en la que confías, como la AC interna de tu empresa. En el siguiente extracto de código, se muestra cómo configurar tu app para una AC personalizada en 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 la AC autofirmado o no público, en formato PEM o DER, a res/raw/my_ca.

Cómo limitar el conjunto de AC de confianza

Si no deseas que tu app confíe en todas las AC en las que confía el sistema, puedes especificar un conjunto reducido de AC en las que puede confiar. Esto brinda protección a la app ante certificados fraudulentos emitidos por cualquiera de las demás AC.

La configuración para limitar el conjunto de AC de confianza es similar a confiar en una AC personalizada para un dominio específico, con la excepción de que se proporcionan varias AC en el recurso. En el siguiente extracto de código, se muestra cómo limitar el conjunto de AC de confianza de tu app en 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 AC de confianza, en formato PEM o DER, a res/raw/trusted_roots. Ten en cuenta que, si usas el formato PEM, el archivo debe contener solo datos PEM, sin texto adicional. También puedes proporcionar varios elementos <certificates> en lugar de solo uno.

Cómo confiar en AC adicionales

Es posible que quieras que tu app confíe en AC adicionales en las que el sistema no confía, por ejemplo, si el sistema aún no incluye la AC o esta no cumple con los requisitos de inclusión del sistema Android. Puedes especificar varias fuentes de certificado para una configuración en res/xml/network_security_config.xml con un código como el siguiente extracto.

<?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 AC para depuración

Cuando depures una app que se conecte a través de HTTPS, recomendamos que te conectes a un servidor de desarrollo local que no tenga el certificado SSL de tu servidor de producción. Para poder hacerlo sin tener que modificar el código de tu app, puedes especificar AC de solo depuración a las cuales se les otorgue confianza únicamente cuando android:debuggable sea true, con debug-overrides. 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.

En el siguiente extracto, se muestra cómo especificar AC de solo depuración en 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>

Inhabilita el tráfico de texto simple

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 con texto simple está inhabilitada de forma predeterminada.

Si deseas que tu app se conecte a destinos usando solo conexiones seguras, puedes inhabilitar la compatibilidad con texto simple (con el protocolo HTTP sin encriptar en lugar de HTTPS) para esos destinos. Esta opción ayuda a prevenir las regresiones accidentales en apps debido a cambios en URLs que generaron fuentes externas, como servidores backend. Consulta NetworkSecurityPolicy.isCleartextTrafficPermitted() para obtener más información.

Por ejemplo, es posible que desees que tu app se asegure de que las conexiones a secure.example.com siempre se realicen a través de HTTPS para proteger el tráfico sensible de redes hostiles.

En el siguiente extracto, se muestra cómo inhabilitar el texto simple en 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 AC preinstaladas. Si alguna de estas AC emitiera un certificado fraudulento, la app estaría en riesgo ante un atacante en la ruta. Algunas apps eligen limitar el conjunto de certificados que aceptan, ya sea a través de la limitación del conjunto de AC en el que confían o la fijación de certificados.

La fijación de certificados se realiza proporcionando 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 AC (al fijar un certificado de la AC 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 permitir que los atacantes omitan los certificados fijados.

En el siguiente extracto, se muestra cómo fijar certificados en 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.

Por ejemplo, los valores que no se establecen en un elemento domain-config se obtienen del elemento domain-config principal si están anidados o del elemento base-config si no lo están. Los valores no establecidos en base-config usan los valores predeterminados de la plataforma.

Por ejemplo, considera un caso en el que todas las conexiones a subdominios de example.com deben usar un conjunto personalizado de AC. Además, el tráfico de texto simple a estos dominios se permite, salvo durante la conexión a secure.example.com. Al anidar la configuración para secure.example.com dentro de la configuración para example.com, trust-anchors no necesita duplicación.

En el siguiente extracto, se muestra cómo se vería este anidamiento en 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:
Es la configuración predeterminada que usan todas las conexiones cuyo destino no está abarcado 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 anidados <domain-config>
descripción:
Configuración usada para conexiones con destinos específicos, como los definidos por elementos domain.

Ten en cuenta que, si varios elementos 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 coincide con el dominio y con todos los subdominios, incluidos los de subdominios. De lo contrario, solo se aplicará la regla a coincidencias exactas.

<debug-overrides>

sintaxis:
<debug-overrides>
    ...
</debug-overrides>
puede contener:
0 o 1 <trust-anchors>
descripción:
Anulaciones que se deben aplicar cuando android:debuggable es "true", lo cual generalmente se atribuye a las compilaciones no comerciales generadas por herramientas de IDE y de compilación. Las anclas de confianza especificadas 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 una de estas anclas de confianza de solo depuración. Si android:debuggable es "false", esta sección se omite por completo.

<trust-anchors>

sintaxis:
<trust-anchors>
...
</trust-anchors>
puede contener:
Cualquier cantidad de <certificates>
descripción:
Conjunto de anclas 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 la AC. 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 la AC preinstalados del sistema.
  • "user" para certificados de la AC agregados por el usuario.
overridePins

Especifica si las AC 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 AC de esa fuente. Esto puede ser útil para depurar AC o para realizar pruebas de ataques de intermediarios en el tráfico seguro de tu app.

De forma predeterminada, es "false" a menos que se especifique en un elemento debug-overrides, en cuyo caso el valor predeterminado es "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
Es la fecha, en formato yyyy-MM-dd, en la que caducan las fijaciones, con lo cual se inhabilita la fijación. 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 del resumen 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