Trusting all certificates allows anybody to do a man in the middle attack

Mobile app security is definitely an area where paranoia makes sense. A not so hypothetical scenario; we are trying to make a get API call and are getting the following error:

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

We panic. Search for help and find the following solution:

// 1
class TrustAllTrustManager : X509TrustManager {
    @SuppressLint("TrustAllX509TrustManager")
    override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {}

    @SuppressLint("TrustAllX509TrustManager")
    override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {}

    override fun getAcceptedIssuers(): Array<X509Certificate> {
        return emptyArray()
    }
}

Should we implement this solution in our code?

Absolutely not!

Trusting all certificates allows anybody to do a man in the middle attack. So what should we do instead?

We should add a Network Security Configuration file.

  • Add res/xml/network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">monkey.work</domain>
        <trust-anchors>
            <certificates src="@raw/trusted_roots"/>
        </trust-anchors>
    </domain-config>
</network-security-config>
  • To the application section of AndroidManifest.xml add
    <application
        android:networkSecurityConfig="@xml/network_security_config"
  • Add res/raw/trusted_roots
  • The file may contain multiple certificates
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
  • To extract all certificates from a server
echo | openssl s_client -showcerts -servername monkey.work -connect monkey.work:443 2>&1 | \
   sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > monkey.work.pem

FAQ

Why is it dangerous to trust all SSL certificates in an Android app?
Implementing a TrustAllTrustManager that accepts any certificate completely disables TLS validation, which allows anyone on the network to perform a man-in-the-middle attack and intercept or modify traffic from your app.
How should I fix the 'Trust anchor for certification path not found' error safely?
Instead of trusting all certificates, define a proper Network Security Configuration that pins trusted roots or certificates for your domain, reference it from AndroidManifest.xml, and store the actual root certificates in res/raw so only expected CAs are accepted.

Welcome to The infinite monkey theorem

Somewhere a monkey just typed Shakespeare in TypeScript. Be the first to read the masterpieces (and the hilarious misfires) landing on the blog.

Subscribe to The infinite monkey theorem

We fling fresh posts—no banana peels attached—straight to your inbox.