From 06aabf4eb82823cd2d7035c179fd96bfa53f07e1 Mon Sep 17 00:00:00 2001
From: Chad Brubaker The Android Network Security Config lets apps customize their network security settings
+in a safe, declarative configuration file without modifying application code.
+These settings can be configured for specific domains and app-wide. An application may want to trust a custom set of CAs instead of the platform
+default. The most common reasons of this are:
+In this document
+
+Features
+
+
+
+Examples
+Trusting Custom CAs
+
+
+
By default secure (e.g. TLS, HTTPS) connections from all applications trust the pre-installed system CAs, and +applications targeting API level 23 (Android M) and below also trust the user-added CA store by default. +An application can customize its own connections using {@code base-config} (for app-wide customization) or +{@code domain-config} (for per-domain customization).
+ +Assume you want to connect to your host which uses a self-signed SSL certificate or to +a host whose SSL certificate is issued by a non-public CA which you trust, e.g., your company's internal +CA.
+
+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> ++ +
Add the self-signed or non-public CA certificate, in PEM or DER format, to {@code res/raw/my_ca}.
+
+In AndroidManifest.xml reference the above config
+
+<?xml version="1.0" encoding="utf-8"?> +... +<application ...> + <meta-data android:name="android.security.net.config" + android:resource="@xml/network_security_config" /> + ... ++ +
An application that does not want to trust all CAs trusted by system can instead specify its own +reduced set of CAs to trust. This protects the application from fradulent certificates issued by any +of the other CAs.
+ +The config to limit the set of trusted CAs is similar to trusting a custom CA +for a specific domain except that multiple CAs are provided in the resource.
+ +
+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> ++ +
Add the trusted CAs, in PEM or DER format, to {@code res/raw/trusted_roots}.
+Note that if using PEM format the file must contain only PEM data and no extra text.
+You can also provide multiple <certificates> elements instead
+of one.
+In AndroidManifest.xml reference the above config
+
+<?xml version="1.0" encoding="utf-8"?> +... +<application ...> + <meta-data android:name="android.security.net.config" + android:resource="@xml/network_security_config" /> + ... ++ + +
An application may want to trust additional CAs not trusted by the system, this could be due to +the system not yet including the CA or a CA that does not meet the requirements for inclusion into +the Android system. An application can do this by specifying multiple certificate sources for a configuration. +
+
+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> ++ +
+In AndroidManifest.xml reference the above config
+
+<?xml version="1.0" encoding="utf-8"?> +... +<application ...> + <meta-data android:name="android.security.net.config" + android:resource="@xml/network_security_config" /> + ... ++ + +
When debugging an application that connects over HTTPS you may want to connect to a local development +server, which does not have the SSL certificate for your production server. In order to support this +without any modification to your application's code you can specify debug-only CAs that are +only trusted when android:debuggable +is {@code true} by using {@code debug-overrides}. Normally IDEs and build tools set this flag automatically for non-release builds.
+This is safer than the usual conditional code because, as a security precaution, application stores +do not accept applications which are marked debuggable.
+ +
+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> ++ +
+In AndroidManifest.xml reference the above config
+
+<?xml version="1.0" encoding="utf-8"?> +... +<application ...> + <meta-data android:name="android.security.net.config" + android:resource="@xml/network_security_config" /> + ... ++ + +
Applications which intend to connect to destinations using only secure connections can opt-out +of supporting cleartext (i.e. plain HTTP instead of HTTPS) to those destinations. This helps prevent +accidental regressions in applications due to changes in URLs provided by external sources such as +backend servers.
+See {a href="{@docRoot}reference/android/security/NetworkSecurityPolicy.html#isCleartextTrafficPermitted()} for more details.
+ +For example, an application may want to ensure that all connections to {@code secure.example.com} are always +done over HTTPS to protect sensitive traffic from hostile networks.
+ +
+res/xml/network_security_config.xml:
+
+<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config usesCleartextTraffic="false"> + <domain includeSubdomains="true">secure.example.com</domain> + </domain-config> +</network-security-config> ++ +
+In AndroidManifest.xml reference the above config
+
+<?xml version="1.0" encoding="utf-8"?> +... +<application ...> + <meta-data android:name="android.security.net.config" + android:resource="@xml/network_security_config" /> + ... ++ + +
Normally an application trusts all preinstalled CAs. If any of these CAs were to issue a fradulent certificate +the application would be at risk from a MiTM attack. Some applications choose to limit the set of +certificates they accept by either limiting the set of CAs they trust or by certificate pinning.
+ +Certificate pinning is done by providing a set of certificates by hash of the public key (SubjectPublicKeyInfo +of the X.509 certificate). A certificate chain is then only valid if the certificate chain contains at least +one of the pinned public keys.
+ +Note that when using certificate pinning you should always include a backup key so that if you +are forced to switch to new keys, or change CAs (when pinning to a CA certificate or an intermediate of that CA), +your application's connectivity is unaffected. Otherwise you will have to push out an update to the +application to restore connectivity.
+ +Additionally it is possible to set an expiration time for pins after which pinning will not be +performed. This helps prevent connectivity issues in applications which have not been updated. +However, setting an expiration time on pins may enable pinning bypass. +
+ +
+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> + </domain-config> +</network-security-config> ++ +
+In AndroidManifest.xml reference the above config
+
+<?xml version="1.0" encoding="utf-8"?> +... +<application ...> + <meta-data android:name="android.security.net.config" + android:resource="@xml/network_security_config" /> + ... ++ + +
Values not set in a specific config will be inherited. +This allows more complex configurations while keeping the configuration file readable.
+ +If a value is not set in a specific entry then value from the next more general entry will be used. +Values not set in a {@code domain-config} will be taken from the parent {@code domain-config}, if nested, or +from the {@code base-config} if not. Values not set in the {@code base-config} will use +the platform default values. + +
For example consider, where all connections to subdomains of {@code example.com} +must use a custom set of CAs. Additonally cleartext traffic to these domains is permitted +except when connecting to {@code secure.example.com}. By nesting the configuration +for {@code secure.example.com} inside the configuration for {@code example.com} the +{@code trust-anchors} does not need to be duplicated.
+ +
+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> ++ +
+In AndroidManifest.xml reference the above config
+
+<?xml version="1.0" encoding="utf-8"?> +... +<application ...> + <meta-data android:name="android.security.net.config" + android:resource="@xml/network_security_config" /> + ... ++ + +
The configuration file is XML. Here is what it can contain:
+ ++<?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> ++ +
<base-config>
+<domain-config>
+<debug-overrides>
+<base-config usesCleartextTraffic=["true" | "false"]> + ... +</base-config>
<trust-anchors>domain-config.
+
+Any values that are not set will use the platform default values. +The default configuration for applications targeting above API level 24 and above: +
+<base-config usesCleartextTraffic="true"> + <trust-anchors> + <certificates src="system" /> + </trust-anchors> +</base-config> ++The default configuration for applications targeting API level 23 and below is: +
+<base-config usesCleartextTraffic="true"> + <trust-anchors> + <certificates src="system" /> + <certificates src="user" /> + </trust-anchors> +</base-config> ++ +
<domain-config usesCleartextTraffic=["true" | "false"]> + ... +</domain-config>
<domain>
+<trust-anchors>
+<pin-set>
+<domain-config>Note that if multiple {@code domain-config} elements cover a destination the config with the most specific (longest) +matching domain rule will be used.
<domain includeSubdomains=["true" | "false"]>example.com</domain>
<debug-overrides> + ... +</debug-overrides>
<trust-anchors><trust-anchors> +... +</trust-anchors> +
<certificates><certificates src=["system" | "user" | "raw resource"] + overridePins=["true" | "false"] /> +
+Default is {@code "false"} unless specified in a {@code debug-overrides} element, in which case the default is {@code "true"}. +
+<pin-set expiration="date"> +... +</pin-set> +
<pin><pin> for the format of pins.Expiration helps prevent connectivity issues in applications which do not get updates to their +pin set, for example because the user disabled application updates.
+<pin digest=["SHA-256"]>base64 encoded digest of X.509 SubjectPublicKeyInfo (SPKI)</pin>