DEV Community


Certificate Pinning in Android

mplacona profile image Marcos Placona Originally published at ・2 min read

Certificate pinning is a security mechanism which allows HTTPS websites and applications using HTTPS services to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates.

With certificate pinning it is possible to mitigate or severely reduce the effectiveness of MiTM attacks enabled by spoofing a back-end server's SSL certificate.

If you are already using API's or services with OkHTTP or any library that uses it, such as Retrofit or Picasso the good news is that you're already half way there.

Let's look at the following example from the documentation:

private final OkHttpClient client = new OkHttpClient();
public void run(String url) throws Exception {
    Request request = new Request.Builder()

    client.newCall(request).enqueue(new Callback() {
        public void onFailure(Call call, IOException e) {
            Log.e(TAG, "onFailure: " + e.getMessage());

        public void onResponse(Call call, okhttp3.Response response) throws IOException {
            Log.d(TAG, "onResponse: " + response.body().string());

Enter fullscreen mode Exit fullscreen mode

And you'd run it like this:

Enter fullscreen mode Exit fullscreen mode

At this point you think:

Great! I'm going though HTTPS, so this must be safe right?

Well... No.

With enough knowledge about proxies (N.B. I have barely just enough), one can intercept that request and see every incoming and outgoing packages... As plain text!


Now if we change our client slightly we can add certificate pinning to it, which will make it way harder for someone to impersonate our certificate and our app will refuse to make requests through that certificate.

private CertificatePinner certificatePinner = new CertificatePinner.Builder()
    .add("", "sha256/0jQVmOH3u5mnMGhGRUCmMKELXOtO9q8i3xfrgq3SfzI")

private final OkHttpClient client = new OkHttpClient
Enter fullscreen mode Exit fullscreen mode


And your code will error and log a message like this.

E/MainActivity: onFailure: Certificate pinning failure!
Peer certificate chain:
sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=:,OU=PositiveSSL,OU=Domain Control Validated
sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
Pinned certificates for

And this is great! Because it tells us which SHA256 hash we should be using. So now we can change our code to use the keys described on the error as follows:

private CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.add("", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=")
.add("", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=")

And sure enough, if you run your code again everything should work as expected
but with an added bonus. Our code is now checking that the certificate of the
host matches with the one we're expecting. And if it doesn't, it will refuse to make a request.

A proxy would then return a message saying: No request was made. Possibly the SSL certificate was rejected..


And now we've pinned our certificate to our code.

Discussion (3)

Editor guide
nateowami profile image
Nathaniel Paulus

Thank you! For a long time I've been wondering whether this type of protection was feasible. So glad to hear it is possible, and what's more, Android supports it without needing an extra library. Really enjoyed finally learning that "my idea" is actually a thing.

mplacona profile image
Marcos Placona Author

Really glad it was helpful to you!

lovis profile image

Great article, thanks for that!
One small issue, though: I think the first image (below "and see every incoming and outgoing packages... As plain text!") should be a different one. 🙂