Reputation: 29017
I have read Android 8: Cleartext HTTP traffic not permitted, but none of the answers appear to allow me to do what I want.
I have an Android application where another client can identify itself with a certificate. The application wants to verify that certificate. Part of verifying the certificate is fetching the certificate revocation list (CRL) from the certificate issuer. The distribution point(s) for the CRL is(are) listed in the certificate, and is inevitably an HTTP URL (the CRL itself is signed by the issuer so there is no security issue, and if it was an HTTPS URL, one would want to verify the certificate protecting the CRL distribution point, and check if it had been revoked ...)
Possible solutions, and why they don't work for me:
network_security_config.xml
which lists the domains to which HTTP is allowed. Sadly, I don't know the URLs when I build the application - it depends on what the CA decides to put in their certificates.android:usesCleartextTraffic="true"
in the manifest. This means that any traffic can be HTTP, and I would rather avoid that if possible. (As an example, communication with the server absolutely must be HTTPS, and I would like an error if I do HTTP by accident.)Is there any way for the code to say "this connection is allowed to be HTTP" (but default to HTTPS only)?
Upvotes: 5
Views: 4931
Reputation: 13019
The documentation on NetworkSecurityPolicy.isCleartextTrafficPermitted() says
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 Socket API will honor this flag because it cannot determine whether its traffic is in cleartext.
So maybe this is an option for you: fetch the CRL using a Socket
. There is a post by Daniel Nugent describing how to set up a simple TCP client
Upvotes: 1
Reputation: 866
If you're using OkHttp, you can construct a client as such:
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS))
.build();
This will only allow connections through HTTPS. So then, you can use your third option (android:usesCleartextTraffic="true"
) and when you make a cleartext connection through this client, it will fail.
Finally, you can create a standard OkHttp client:
OkHttpClient client = new OkHttpClient.Builder().build()
when you want to use the cleartext connection.
EDIT: Using HttpUrlConnection
, you can simply check if the returned connection is a HttpsUrlConnection
, like:
try {
URL my_url = new URL(path);
HttpUrlConnection urlConnection = (HttpURLConnection) my_url.openConnection();
if(!(urlConnection instanceof HttpsURLConnection)) {
// cleartext connection, throw error
throw new NotHttpsException();
}
// the connection is secure, do normal stuff here
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(1500);
urlConnection.setReadTimeout(1500);
result = IOUtil.readFully(urlConnection.getInputStream());
} catch(Exception e) {
e.printStackTrace()
} finally {
if(urlConnection != null) urlConnection.disconnect();
}
Upvotes: 1
Reputation: 5589
Tha app has a TLS connection with the server.
You can ask the server to hand off those CRL urls to you (It is handing off the certificate in the first place right?).
It could even do it before hand and provide the Certificate together with the CRLs.
In this way you get the CRLs without loosing the https lock nor having to make exceptions.
Upvotes: 0