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 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
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
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.
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.
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
<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
openssl x509 -in koz.io.pem.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
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 (
- user trust store (
- 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.