Setting domain name of network_security_config.xml to localhost at runtime

Remy picture Remy · Jan 10, 2020 · Viewed 14.8k times · Source

Since Android 9, Android by default only allows network connections over HTTPS. However the only requests i'm doing are done over the localhost (e.g http://10.41.199.226:port/FooBar) which is handled by a (C#)HttpListener listening to that address:port combination.

Since this request is made over HTTP Android doesn't by default allow it. Following this documentation by Android about the network_security_config file I can allow HTTP connections by adding the following network_security_config.xml file

<?xml version="1.0" encoding="utf-8"?>
 <network-security-config>
   <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
    <debug-overrides>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>

Which is called from the Android manifest using android:networkSecurityConfig="@xml/network_security_config".

This allows the HTTP request to be completed, however because this sets the base-config it allows HTTP requests to be made across the entire app. This isn't a good idea seeing I may want to add outgoing requests in the future, which I would want to be over HTTPS and would like this safety net to be in place for that. Making this a no-go.

Further on in that same document they introduce the domain-config which allows you to set the cleartextTrafficPermitted depending on the domain, which I tried with the following domains set

<?xml version="1.0" encoding="utf-8"?>
 <network-security-config>
    <domain-config cleartextTrafficPermitted="true">
      <domain includeSubdomains="true">127.0.0.1</domain>
      <domain includeSubdomains="true">10.0.0.1</domain>
      <domain includeSubdomains="true">localhost</domain>
    </domain-config>
</network-security-config>

With no results, requests were still getting blocked due to not being https.

I looked up the device's local address, and added it to the domains list

<domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.41.199.226</domain> <!--assume this is my local ip -->
</domain-config>

This worked, and HTTP was allowed only when requested over the localhost, while any outgoing request would this require HTTPS.

The only problem with this is is that I have no way of knowing the local ip off the device that'll run the app before the app is launched.

So my question is, is there a way to either:

  1. Set the domain name to something that'll automatically register as the local ip? (something like localhost as I tried, but which didn't work)
  2. Add a "wildcard" IP address that'll accept any IP within the 10.x.x.x range (I had hoped setting includeSubdomains="true" would do this for me when adding a 10.0.0.0 address. But it doesn't)
  3. As a final resort, is it possible to edit the network_security_config.xml file at runtime, so I can dynamically update the domain name of one of the domain entries to the current local ip, when launching the app?

The app is developed using Unity 2019.1.8 using the .net 4.x IL2CPP scripting runtime

Answer

Kalpesh Rupani picture Kalpesh Rupani · Jan 20, 2020

The easy way to implement this is to use this attribute to your AndroidManifest.xml where you allow all http for all requests:

android:usesCleartextTraffic="true"

But in case you want some more configurations for different links for instance, allowing http for some domains but not other domains you must provide networkSecurityConfig file.

To do this in Android 9 Pie you will have to set a networkSecurityConfig in your Manifest application tag like this:

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




    </application>
</manifest>

Then in your xml folder you now have to create a file named network_security_config just like the way you have named it in the Manifest and from there the content of your file should be like this to enable all requests without encryptions:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

From there you are good to go. Now your app will make requests for all types of connections. For additional information on this topic https://developer.android.com/training/articles/security-config.