Android Network Security Configuration

Android Network Security Configuration

[[198282]]

The Network Security Configuration feature allows applications to customize their network security settings in a secure declarative configuration file without modifying the application code. These settings can be configured for specific domains and specific applications. The main functions of this feature are as follows:

  • Custom trust anchors: Customize which certificate authorities (CAs) are trusted for your app's secure connections. For example, trust specific self-signed certificates or limit the set of public CAs that your app trusts.
  • Debug-only override: Debug secure connections in your app in a safe way without adding risk to installed users.
  • Clear text communication opt-out: Prevent apps from accidentally using clear text communication.
  • Certificate pinning: Limit your app's secure connections to specific certificates.

Adding a Security Profile

The Network Security Configuration feature uses an XML file in which you can specify settings for your app. You must include an entry in your app's manifest to point to this file. The following code excerpt from a manifest shows how to create this entry:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <manifest ... >
  3. <application android:networkSecurityConfig= "@xml/network_security_config"  
  4. ... >
  5. ...
  6. </application>
  7. </manifest>

Custom trusted CA

An application may need to trust a custom set of CAs instead of the platform defaults. The most common reasons for this are:

  • Connecting to a host with a custom certificate authority, such as a self-signed or internally-signed CA.
  • Limit your CA set to only those CAs you trust, rather than every pre-installed CA.
  • Trust additional CAs that are not included in the system.

By default, secure connections from all apps (using protocols such as TLS and HTTPS) trust the preinstalled system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust user-added CA stores by default. Apps can customize their own connections using base-config (app-wide customization) or domain-config (per-domain customization).

Configuring a Custom CA

Suppose you want to connect to a host that uses a self-signed SSL certificate, or a host whose SSL certificate was issued by a non-public CA that you trust, such as your company's internal CA.

res/xml/network_security_config.xml:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <domain-config>
  4. <domain includeSubdomains= "true" >example.com</domain>
  5. <trust-anchors>
  6. <certificates src= "@raw/my_ca" />
  7. </trust-anchors>
  8. </domain-config>
  9. </network-security-config>

Add a self-signed or non-public CA certificate in PEM or DER format to res/raw/my_ca.

Limit the set of trusted CAs

If the application does not want to trust all CAs trusted by the system, it can specify a narrow set of CAs to trust. This prevents the application from trusting fraudulent certificates issued by any other CA.

The configuration for restricting the set of trusted CAs is similar to trusting a custom CA for a specific domain, except that multiple CAs are available in the resource.

res/xml/network_security_config.xml:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <domain-config>
  4. <domain includeSubdomains= "true" >secure.example.com</domain>
  5. <domain includeSubdomains= "true" >cdn.example.com</domain>
  6. <trust-anchors>
  7. <certificates src= "@raw/trusted_roots" />
  8. </trust-anchors>
  9. </domain-config>
  10. </network-security-config>

Add the trusted CAs to res/raw/trusted_roots in PEM or DER format. 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 just one.

Trust Additional CA

An application may need to trust additional CAs that the system does not trust, either because the system does not include the CA or because the CA does not meet the requirements for being added to the Android system. An application can do this by specifying multiple certificate sources for a configuration.

res/xml/network_security_config.xml:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <base-config>
  4. <trust-anchors>
  5. <certificates src= "@raw/extracas" />
  6. <certificates src= "system" />
  7. </trust-anchors>
  8. </base-config>
  9. </network-security-config>

Configuring CA for debugging

When debugging an app connected over HTTPS, you may need to connect to a local development server that does not provide an SSL certificate for the production server. To support this without making any modifications to your app's code, you can specify debug-only CAs that are trusted only when android:debuggable is true by using debug-overrides. Typically, IDEs and build tools automatically set this flag for non-release builds.

This is safer than normal conditional code, because the App Store does not accept apps marked as debuggable for security reasons.

res/xml/network_security_config.xml:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <debug-overrides>
  4. <trust-anchors>
  5. <certificates src= "@raw/debug_cas" />
  6. </trust-anchors>
  7. </debug-overrides>
  8. </network-security-config>

Opt out of clear text communications

Applications that are designed to connect to destinations that use only secure connections can opt out of providing cleartext (using the decrypted HTTP protocol instead of HTTPS) support for those destinations. This option helps prevent applications from unexpected regressions due to changes in URLs provided by external sources (such as backend servers). See NetworkSecurityPolicy.isCleartextTrafficPermitted() for more details.

For example, an application might want to ensure that all connections to secure.example.com are always done over HTTPS to prevent sensitive traffic from malicious networks.

res/xml/network_security_config.xml:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <domain-config cleartextTrafficPermitted= "false" >
  4. <domain includeSubdomains= "true" >secure.example.com</domain>
  5. </domain-config>
  6. </network-security-config>

Pinning Certificates

Typically, apps trust all pre-installed CAs. If a pre-installed CA issues a fraudulent certificate, the app is at risk of being attacked by a man-in-the-middle attack. Some apps choose to limit the set of certificates they accept by limiting the set of trusted CAs or by using certificate pinning.

Certificate pinning is done by providing a set of certificates by hash value of the public key (SubjectPublicKeyInfo of the X.509 certificate). Then, the certificate chain is valid only if it 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 a new key or change CAs (when pinning to a CA certificate or an intermediate certificate of that CA), your app's connectivity is not affected. Otherwise, you must push an update to your app to restore connectivity.

Additionally, you can set a pinned expiration time after which certificate pinning is not performed. This helps prevent connectivity issues for apps that have not yet been updated. However, setting a pinned expiration time may bypass certificate pinning.

res/xml/network_security_config.xml:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <domain-config>
  4. <domain includeSubdomains= "true" >example.com</domain>
  5. <pin- set expiration= "2018-01-01" >
  6. <pin digest= "SHA-256" >7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
  7. <! -- backup pin -->  
  8. <pin digest= "SHA-256" >fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
  9. </pin-set>
  10. </domain-config>
  11. </network-security-config>

Configuring inheritance behavior

Values ​​not set in a specific configuration will be inherited. This behavior allows for more complex configurations while keeping the configuration files readable.

If a value is not set in a specific entry, the value from the more general entry will be used. For example, values ​​not set in domain-config will be taken from the parent domain-config (if nested) or base-config (if not nested). Values ​​not set in base-config will use the platform default.

For example, all connections to subdomains of example.com must use the custom CA set. Additionally, clear text traffic using these domains is allowed except when connecting to secure.example.com. By nesting the configuration for secure.example.com within the configuration for example.com, trust-anchors do not need to be repeated.

res/xml/network_security_config.xml:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <domain-config>
  4. <domain includeSubdomains= "true" >example.com</domain>
  5. <trust-anchors>
  6. <certificates src= "@raw/my_ca" />
  7. </trust-anchors>
  8. <domain-config cleartextTrafficPermitted= "false" >
  9. <domain includeSubdomains= "true" >secure.example.com</domain>
  10. </domain-config>
  11. </domain-config>
  12. </network-security-config>

Configuration file format

The network security configuration feature uses an XML file format. The overall structure of the file is shown in the following code example:

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2. <network-security-config>
  3. <base-config>
  4. <trust-anchors>
  5. <certificates src= "..." />
  6. ...
  7. </trust-anchors>
  8. </base-config>
  9.  
  10. <domain-config>
  11. <domain>android.com</domain>
  12. ...
  13. <trust-anchors>
  14. <certificates src= "..." />
  15. ...
  16. </trust-anchors>
  17. <pin-set>
  18. <pin digest= "..." >...</pin>
  19. ...
  20. </pin-set>
  21. </domain-config>
  22. ...
  23. <debug-overrides>
  24. <trust-anchors>
  25. <certificates src= "..." />
  26. ...
  27. </trust-anchors>
  28. </debug-overrides>
  29. </network-security-config>

The following sections describe additional details of the syntax and file format.

<network-security-config>

  • Can contain:
  • 0 or 1 <base-config>
    • Any number of <domain-config>
    • 0 or 1 <debug-overrides>

<base-config>

  • grammar:
  1. <base-config cleartextTrafficPermitted=[ "true" | "false" ]>
  2. ...
  3. </base-config>
  • Can contain:

<trust-anchors>

  • illustrate:

The default configuration used for all connections whose destinations are not covered by domain-config. Any values ​​not set use the platform default. The default configuration for apps targeting Android 7.0 (API level 24) and higher is as follows:

  1. <base-config cleartextTrafficPermitted= "true" >
  2. <trust-anchors>
  3. <certificates src= "system" />
  4. </trust-anchors>
  5. </base-config>

The default configuration for apps targeting Android 6.0 (API level 23) and lower is as follows:

  1. <base-config cleartextTrafficPermitted= "true" >
  2. <trust-anchors>
  3. <certificates src= "system" />
  4. <certificates src= "user" />
  5. </trust-anchors>
  6. </base-config>

<domain-config>

  • grammar:
  1. <domain-config cleartextTrafficPermitted=[ "true" | "false" ]>
  2.  
  3. ...
  4.  
  5. </domain-config>
  • Can contain:
    • 1 or more <domain>
    • 0 or 1 <trust-anchors>
    • 0 or 1 <pin-set>
  • Any number of nested <domain-config>
  • illustrate

Configuration used to connect to a specific destination as defined by the domain element. Note that if there are multiple domain-config elements covering a destination, the most specific (longest) configuration matching the domain rule will be used.

<domain>

  • grammar:
  1. <domain includeSubdomains=[ "true" | "false" ]>example.com</domain>
  • property:
    • includeSubdomains
    • If "true", this domain rule will match the domain and all subdomains (including subdomains of subdomains). Otherwise, the rule will only apply to exact matches.
  • illustrate:

<debug-overrides>

  • grammar:
  1. <debug-overrides>
  2.  
  3. ...
  4.  
  5. </debug-overrides>
  • Can contain:
    • 0 or 1 <trust-anchors>
  • illustrate:

Overrides that are applied when android:debuggable is "true", which is typically the case for non-release builds produced by IDEs and build tools. The trust anchors specified in debug-overrides will be added to all other configurations, and certificate pinning will not be performed when the server's certificate chain uses one of the debug-only trust anchors. If android:debuggable is "false", this section will be ignored entirely.

<trust-anchors>

  • grammar:
  1. <trust-anchors>
  2.  
  3. ...
  4.  
  5. </trust-anchors>
  • Can contain:

Any number of <certificates>

  • illustrate:

The set of trust anchors used for secure connections.

<certificates>

  • grammar:
  1. <certificates src=[ "system" | "user" | "raw resource" ]
  2.  
  3. overridePins=[ "true" | "false" ] />
  • illustrate:

The set of X.509 certificates to use with the trust-anchors element.

  • property:
    • src
    • The source of the CA certificate. Each certificate can be one of the following:
      • A raw resource ID pointing to a file containing an X.509 certificate. The certificate must be encoded in DER or PEM format. If it is a PEM certificate, the file must not contain additional non-PEM data, such as comments.
      • "system" for preinstalling system CA certificates
      • "user" for user-added CA certificates
    • overridePins
    • Specifies whether certificate pinning is bypassed for this origin's CA. If "true", certificate pinning is not performed for certificate chains signed by this origin's CA. This is useful for debugging CAs or testing man-in-the-middle (MiTM) attacks on your application's secure traffic. The default value is "false", unless otherwise specified in the debug-overrides element, in which case it defaults to "true".

<pin-set>

  • grammar:
  1. <pin- set expiration= "date" >
  2.  
  3. ...
  4.  
  5. </pin-set>
  • Can contain:

Any number of <pin>

  • illustrate:

A set of public key pins. For a secure connection to be trusted, there must be a public key in the trust chain that is in the pinned set. See <pin> for the pinning format.

  • property:
    • expiration
    • The date in the format yyyy-MM-dd on which the pinning expires, thus deactivating the pinning. If this property is not set, the pinning does not expire. Setting an expiration time helps prevent connectivity issues for apps that are not updated to their pinned set (for example, when the user disables app updates).

<pin>

  • grammar:
  1. <pin digest=[ "SHA-256" ]>base64 encoded digest of X.509
  2.  
  3. SubjectPublicKeyInfo (SPKI)</pin>
  • property:
    • digest
    • Used to generate a fixed digest algorithm. Currently only "SHA-256" is supported.

<<:  Difficulties in JavaScript from the perspective of direction

>>:  Rich text editor implemented using UITableView in iOS

Recommend

Can we genetically modify pests to make them 're-insects'?

Produced by: Science Popularization China Author:...

8 Classic Models for Event Planning

The May Day holiday is over and everyone has to r...

Xiaohongshu traffic diversion and monetization-Hi Tui Academy

Course Outline 1. Basics 1. Introduction to Xiaoh...

Game live streaming platform: Douyu, Huya competitive product analysis report

In this article, the author attempts to analyze t...

Zhao Yu's "User Experience Design Practical Notes"

When talking about a product, people often use use...

8 ways to promote on Xiaohongshu, shared with you!

I spent 2 months testing, during which I found tw...