You should disable usesCleartextTraffic in Xamarin Android

After a security review I learned an easy tip. By default, Android allows HTTP traffic on older versions of Android! It’s super simple to disable, and you definitely should.

In iOS, HTTP traffic is not allowed. You must make all requests to HTTPS endpoints.

In Android this wasn’t done until Android 9. However, you probably have your Minimum Android version set lower then that. The default for new projects, even today (January 2021) is Android 5.0.

You might think this is fine since you only make HTTPS calls. And, admittedly, this is a very low security risk. However, it is possible that an attack can be done where a 3rd party maliciously sends an HTTP redirect since no certificate is being used. If you don’t want to raise your minimum SDK level and your security review team has very high standards, you’ll want to fix this.

First - the test. We’ll try to grab a string from a server that we know allows HTTP.

    try
    {

        var url = "http://www.httpvshttps.com";
        using var httpClient = new HttpClient();
        var result = await httpClient.GetStringAsync(url);

    }
    catch (Exception ex)
    {

        // iOS: The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.
        // Android 9+: Cleartext HTTP traffic to httpvshttps.org not permitted

        string errorMessage = ex.Message;

    }

On iOS and Android 9+ an exception will occur. However, if you run lower version of Android you’ll see there is no problem grabbing the HTTP content:

To fix this, open your AndroidManifest.xml file. Find the ‘application’ tag (line 4 if you haven’t made any other changes yet) and simply add this

    android:usesCleartextTraffic="false"

So a default AndroidManifest.xml with this change will look like this:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.company.appname">
        <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
        <application android:label="AppName.Android" android:theme="@style/MainTheme" android:usesCleartextTraffic="false"></application>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    </manifest>

And that’s it. If we re-run our test now on an Android device below 9 it will also throw an exception. The ex.Message is slightly different for some reason (CLEARTEXT communication not supported: []) but now we pass our security review!