Moxie Marlinspike >> Blog >> Your app shouldn’t suffer SSL’s problems

PUBLICIDADE


In recent months, Comodo has been
hacked repeatedly, DigiNotar was
compromised, and the security of CAs as a whole has been found to be
not altogether inspiring. The consensus finally seems to be shifting from the notion that CAs are
merely a ripoff, to the notion that they are a ripoff, a security problem, and that we want them
dead as immediately as possible
. The only question that remains is how to replace them.

The Trouble Comes With Generality

We need CA signatures (or an alternative authenticity infrastructure) for general purpose network
communication tools: things like your web browser, command-line SSL clients, mail clients, and IM
clients. These are applications that can make arbitrary SSL connections to whatever destination you
specify, and could not possibly have any advance knowledge of what SSL certificate they should expect
to receive from those arbitrary locations.

Instead, these clients are given advance knowledge of a handful of CA certificates, which then sign
the certificates for all of the arbitrary locations a general purpose network client would like to
connect. As they say, all problems in computer science can be solved by another layer of indirection.

But of course, you really strike out when that abstraction layer fails.

Mobile Is An Escape

One of the interesting things about the mobile environment is that we actually have an opportunity
to write client-side software again. For better or worse, this means that mobile developers are no
longer constrained by the generality of the web browser. This has obviously been explosive in its
opportunity for integration with hardware-backed services like location information, accelerometer
data, camera support, and IPC with other client-side software.

But it also creates a number of security-related opportunities, one of which is the way that mobile
apps do secure communication.

If you have a mobile app that makes SSL connections to a service you control, there is really no
reason to be validating your service’s certificate using CA signatures. Remember, CA signatures are
for general purpose network communication, and that’s not what is happening here. We need an
authenticity infrastructure when there is no way to have advance knowledge of what SSL certificate
a client should expect to see, but your app knows where it will be connecting, and it knows exactly
what it should expect.

Google is already doing this. They have an
“app” called Chrome, and when their app makes SSL connections to their own services, it checks to
make sure that the certificates it sees are the ones it knows Google is using. They call this “pinning,”
and you should do it for your mobile apps.

There are two possible ways to do this on Android, here’s how!

Option 1: Wipe The Page Clean

The first option is to leave CA certificates behind all together. In addition to providing enhanced
security, it feels refreshing.

On the server side, you’ll want to create your own 4096bit signing certificate that you keep offline,
and use it to sign certificates that you generate for your web services. If you’ve got cash, you can
do this with an HSM, otherwise you can just
use OpenSSL and keep the signing
certificate’s key offline.

On the client side, you simply need to distribute the signing certificate with your app and validate
against it. On Android, to distribute it, first create a keystore using keytool:

$ wget http://bouncycastle.org/download/bcprov-jdk16-146.jar
$ keytool -importcert -file your_signing_certificate.pem -keystore yourapp.store -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk16-146.jar -storetype BKS

Put yourapp.store in the “assets” directory of your Android app. Now all you need to do is validate against
it. To make a standard HTTPS request:

private InputStream makeRequest(Context context, URL url) {
  AssetManager assetManager       = context.getAssets();
  InputStream keyStoreInputStream = assetManager.open("yourapp.store");
  KeyStore trustStore             = KeyStore.getInstance("BKS");

  trustStore.load(keyStoreInputStream, "somepass".toCharArray());

  TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
  tmf.init(trustStore);

  SSLContext sslContext = SSLContext.getInstance("TLS");
  sslContext.init(null, tmf.getTrustManagers(), null);

  HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
  urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

  return urlConnection.getInputStream();
}

Or in order to open a straight SSL socket, your code would be similar:

private Socket constructSSLSocket(Context context, String host, int port) {
  AssetManager assetManager        = context.getAssets();
  InputStream keyStoreInputStream  = assetManager.open("yourapp.store");			
  KeyStore trustStore              = KeyStore.getInstance("BKS");

  trustStore.load(keyStoreInputStream, "somepass".toCharArray());

  SSLSocketFactory sslSocketFactory = new SSLSocketFactory(trustStore);
  sslSocketFactory.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

  return sslSocketFactory.connectSocket(sslSocketFactory.createSocket(), host, port, null, 0, new BasicHttpParams());
}

In both cases, you would obviously want to cache your SSLSocketFactory, and there’s some exception
handling to be done. But by implementing something similar to the above, your App has securely opted
out of the CA system entirely.

Option 2: Trust But Verify

If you need to stick with CA-signed certificates for some reason, you can limit the scope of your exposure.
By default, your App likely validates against all of the CA certificates that ship with Android, but that
means any single compromised CA in the total set can potentially compromise your communication (even if it’s
not the CA you’re using). Your App knows what CA you’re using, however, so it can limit trust to signatures
from that CA only (or a small set of CAs as backup).

As explained in Adam Langley’s nice Chrome writeup,
you’ll want to pin the SubjectPublicKeyInfo of the CA certificate you’re using (and perhaps one or two others
as a backup). I’ve put together a small Python script for generating a pin for a certificate,
available here (these are compatible with
Chrome’s pins — thanks are due to Adam Langley for providing his reference implementation in Go).

In order to generate your pin, you would do something similar to:

$ git clone https://github.com/moxie0/AndroidPinning.git
$ cd AndroidPinning
$ python ./pin.py /path/to/cacert.pem

On the Android side, I’ve put together a
simple TrustManager implementation that is layered on top of the default system TrustManager, so that it
continues validating against the system CA certificate store, but can additionally be made to enforce pins
(as generated by you, above).

You can use this PinningTrustManager as follows:

TrustManager[] trustManagers = new TrustManager[1];
trustManagers[0]             = new PinningTrustManager(new String[] {"f30012bbc18c231ac1a44b788e410ce754182513"});

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);

HttpsURLConnection urlConnection = (HttpsURLConnection)new URL("https://encrypted.google.com/").openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

InputStream in = urlConnection.getInputStream();

…where you would, of course, substitute your own pins and destination URL.

By doing this, your App is still vulnerable to the security and whims of the CA certificates you pin,
but at least you’re no longer exposed to the security and whims of all 650 different CAs.

In Conclusion

Either by leaving CAs behind entirely (!), or by limiting exposure to them, anyone doing secure communication
via mobile apps today has an opportunity to move beyond the constraints of the web browser and protect
themselves. Give it a shot.

In the future, hopefully we’ll see solutions to the “general purpose” validation problem (such as
Convergence ) integrated into general purpose clients, along with “general purpose”
certificate pinning solutions (such TACK ).



Fonte: Geral busca Notícias

Mais recentes

PUBLICIDADE