Certificate pinning aims to close a trust problem that comes with PKI architecture: you trust the certificate authority (CA) and assume that the server is valid, because you trust the CA. Certificate pinning aims to ensure that you also can also trust the server. How is pinning going to achieve this? You know the certificates you are going to receive by the server, and validate those certificates with your local information. Sounds complicated, but it means that your client has all the certificates expected to receive from the server (CA certificate, intermediate certificate and server certificate) and when the server sends those certificates, they are all compared to the client’s locally stored ones. If one of those certificates do not match, client will not connect to server.
OWASP has some more useful information on this topic online available
Sometimes you are already using certificate pinning without knowing it. When you import the CA certificate of your enterprise CA into a keystore, you are already partly using certificate pinning. If you also import the certificate of the server to validate the complete chain, you are doing certificate pinning. iOS documentation contains little information on this topic, but with Google help you can find some projects that try to solve this on GitHub    . Android developer guide contains a small section on pinning. Looking at the source code, you can see that a keystore containing only the expected certificates is created.
CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt")); Certificate ca = cf.generateCertificate(caInput);// Create a KeyStore containing our trusted CAsString keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca);
As you can see, certificate pinning is simple to do. A problem is that you need to be able to control the used keystore. This means that you cannot do real certificate pinning in a web only scenario. If your app is 100% HTML5 or a hybrid app, you won’t be able to use your own keystore. This is also true for Cordova apps, as here you are using the web browser to access the TLS secured service, and not a native client. The browser will trust those CAs that are configured for the browser. HTTP Public Key Pinning (HPKP) promises to gain back some of the trust of a native pinning implementation
HTTP Public Key Pinning
With HPKP, a server publishes a set of hashes of his certificates, and a client expects to receive certificates from the server that matches those hashes. In case a CA is compromised, or an attacker can create a false certificate, the fingerprint (hashes) of these certificates is expected to differ, and the client will then not open a connection to the server. Of course, in case the attacker can take of the web server (directly or indirectly), HPKP won’t help. The hashes for HPKP are communicated in a HTTP header: Public-Key-Pins.
There is a RFC for HPKP (RFC 7469), but don’t expect too much. IE/Edge don’t support it; Chromium browser don’t use HPKP for private root CAs. A weak point is the first request: Ensure that HPKP is only send by a secured connection (TLS). And to make HPKP make sense, on the first request, you must hope that the web server wasn’t compromised at that time. If so, you’ll already get an invalid hash. When the server certificate is updated, the hash must be recreated and included in the header. An article by Mozilla describes how to create the hash and how to set the header. Online tools to validate the generated hash are also available  . Some tips on correct usage of HPKP can be found here.