Tuesday 14 January 2020

Setting domain name of network_security_config.xml to localhost at runtime

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



from Setting domain name of network_security_config.xml to localhost at runtime

No comments:

Post a Comment