10 April 2018
Posted by Chad Brubaker, Senior Software Engineer Android Security
Android is committed to keeping users, their devices, and their data safe. One of the ways that we keep data safe is by protecting all data that enters or leaves an Android device with Transport Layer Security (TLS) in transit. As we announced in our Android P developer preview, we're further improving these protections by preventing apps that target Android P from allowing unencrypted connections by default.
This follows a variety of changes we've made over the years to better protect Android users.To prevent accidental unencrypted connections, we introduced the android:usesCleartextTraffic
manifest attribute in Android Marshmallow. In Android Nougat, we extended that attribute by creating the Network Security Config feature, which allows apps to indicate that they do not intend to send network traffic without encryption. In Android Nougat and Oreo, we still allowed cleartext connections.
If your app uses TLS for all connections then you have nothing to do. If not, update your app to use TLS to encrypt all connections. If you still need to make cleartext connections, keep reading for some best practices.
Android considers all networks potentially hostile and so encrypting traffic should be used at all times, for all connections. Mobile devices are especially at risk because they regularly connect to many different networks, such as the Wi-Fi at a coffee shop.
All traffic should be encrypted, regardless of content, as any unencrypted connections can be used to inject content, increase attack surface for potentially vulnerable client code, or track the user. For more information, see our past blog post and Developer Summit talk.
Once your server supports TLS, simply change the URLs in your app and server responses from http:// to https://. Your HTTP stack handles the TLS handshake without any more work.
If you are making sockets yourself, use an SSLSocketFactory instead of a SocketFactory. Take extra care to use the socket correctly as SSLSocket doesn't perform hostname verification. Your app needs to do its own hostname verification, preferably by calling getDefaultHostnameVerifier()
with the expected hostname. Further, beware that HostnameVerifier.verify()
doesn't throw an exception on error but instead returns a boolean result that you must explicitly check.
While you should use TLS for all connections, it's possibly that you need to use cleartext traffic for legacy reasons, such as connecting to some servers. To do this, change your app's network security config to allow those connections.
We've included a couple example configurations. See the network security config documentation for a bit more help.
If you need to allow connections to a specific domain or set of domains, you can use the following config as a guide:
<network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">insecure.example.com</domain> <domain includeSubdomains="true">insecure.cdn.example.com</domain> </domain-config> </network-security-config>
If your app supports opening arbitrary content from URLs over insecure connections, you should disable cleartext connections to your own services while supporting cleartext connections to arbitrary hosts. Keep in mind that you should be cautious about the data received over insecure connections as it could have been tampered with in transit.
<network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">example.com</domain> <domain includeSubdomains="true">cdn.example2.com</domain> </domain-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config>
If your library directly creates secure/insecure connections, make sure that it honors the app's cleartext settings by checking isCleartextTrafficPermitted before opening any cleartext connection.