Android engineers have recently been busy building out AndroidNSSP (Android Network Security Provider): a system that application developers will be able to use in order control aspects of the network security policy of their application. It’s been long overdue, and there are various bits and pieces still missing; however important parts were merged to AOSP master about a month ago.
This is the second part of my previous post on the topic (the war on cleartext traffic).
android.security.net.config
The android.security.net.config
package holds most of the new code. This package contains various new classes used to parse user configuration about the network security policy of an app (from AndroidManifest,xml
or other XML files) and configure the policy. There’s a lot of rework in the networking internals; mainly so that applications use a new NetworkSecurityTrustManager
.
Capabilities
Applications using the new system will be able to control the following for their app context:
- Block clear-text traffic
- Enforce HSTS
- Use Certificate Pinning
- Configure custom Trust Anchors
These configuration options can be application-wide or per-domain.
Permit clear-text traffic
The cleartextTrafficPermitted=False
property will let developers block app traffic that does not happen over a secure channel (e.g. HTTP, FTP, WebSockets, XMPP, IMAP, SMTP without TLS or STARTTLS).
It will also be possible to set this option to False
per domain, allowing for greater granularity. For example you might want to block cleartext traffic to your server but still let advertisement libraries communicate with their backends in any way they want.
The default will be True, allowing cleartext traffic for all.
However, there are various caveats: >This flag is honored on a best effort basis because it’s impossible to prevent all cleartext traffic from Android applications given the level of access provided to them.
For example, there’s no expectation that the java.net.Socket API will honor this flag because it cannot determine whether its traffic is in cleartext. However, most network traffic from applications is handled by higher-level network stacks/components which can honor this aspect of the policy.
NOTE: WebView does not honor this flag.
HSTS enforcement
The hstsEnforced=True
setting will allow developers to enforce HTTP Strict Transport Security for their apps. As many of you know, HSTS is a mitigation control for SSL-Stripping style attacks.
It still allows MitM attacks during the first connection to an unknown host. Browsers attempt to mitigate this attack window via pre-loading HSTS pins for popular websites; unsure how that can work for normal Android apps.
Again, this setting will be configurable per domain or application-wide.
Certificate Pinning
Android has had native Certificate Pinning support since version 4.2. A big thanks to Nikolay Elenkov for his detailed (although a bit dated now) write-up from 2012.
The problem with this pinning implementation is that it’s been practically unused so far: Android applications didn’t have a way to import their own pins unless they had root access to the system.
The new Network Security Policy system fixes this: Applications will be able to configure the pins they want to use, for the domains they want to use them for.
Here is a sample per-domain configuration for koz.io
<domain-config hstsEnforced=[True|False] cleartextTrafficPermitted=[True|False]>
<domain includeSubdomains=[True|False]>koz.io</domain>
<pin-set expiration="exp-date">
<pin digest=sha256>PaJOmDNhWkVBvuXfzqXMyfo7kgtGpcyZp6L8EqvM8Ck=</pin>
</pin-set>
</domain-config>
The pins are base64 encoded SHA-256 hashes of the certificate’s Subject Public Key Info (SPKI) field, as described in RFC7469.
Instructions on generating the pin for the end-entity certificate of koz.io
:
openssl x509 -in koz.io.pem.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
or
openssl s_client -servername koz.io -connect koz.io:443 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
The pinning implementation, as expected, hooks into the default TrustManager’s checkServerTrusted()
; it’s been that way for quite a while but apps so far were not able to use their own pins.
Custom Trust Anchors
Developers will also be able to set up their own custom Trust Anchors to be used for their connections. This is useful in case they are testing against backends with a custom self-signed certificate (instead of disabling validation alltogether), if they plan to move away of the PKI system, if they want to implement a trust-anchor based way of pinning etc.
The system will support loading certificate files from the following sources:
- system trust store (
/etc/security/cacerts
) - user trust store (
cacerts-added
) - keystore file shipped with app
- directory with certificates shipped with the app
- other resource file shipped with the app
The implementation for most of these is not there yet.
Here is a sample application-wide configuration
<base-config hstsEnforced=[True|False] cleartextTrafficPermitted=[True|False]>
<trust-anchors>
<certificates src=["system"|"user"|"resource-id-ref"] overridePins=[True|False]>
</trust-anchors>
</base-config>
You might have noticed the overridePins
property. This gets tricky very quickly: a custom trust anchor may or may not override any pins (for certificate pinning) also set for a particular domain.
######Conclusion I welcome the changes and hope they make it into Android N which is due to be released on May 18. They’ll bring some much needed flexibility and robustness in the Android app networking security situation which is currently messy to say the least.