简体   繁体   中英

SSL Pinning and certificate expiry

This question relates to the use of SSL Pinning in a client app against a web api and certificate expiry.

Scenario :

I own example.com and have a subdomain where an api is hosted, as such: api.example.com

I wish to use the api over SSL , so an SSL Certificate is created for the subdomain.

After the certificate has been acquired, I have:

  • A Public Certificate
  • A Intermediate Certificate
  • A Private Key

It's my understanding that I install these certificates on my webserver.

I then wish for my client app to connect to the api. To mitigate against man-in-the-middle style attacks, I wish to use SSL Pinning, so that the client will only communicate with my api, not someone spoofing it.

In order to pin in the client app, I have two choices, either pin against the public or intermediate certificate.

Let's say I implement this.

What happens when the certificate on api.example.com expires?

It's my understanding that the client app would no longer work.

Do I need to regenerate a complete set of public/intermediate/private items again? and then put a new public or intermediate certificate in the app?

Question :

I would still like the client app to work until the certificate on api.example.com was updated. Of course, a new certificate can be put in the client app, but things like roll-out take time.

How can I handle this?

I've read that Google updates their certificate every month, but somehow manages to keep the public key the same: How to pin the Public key of a certificate on iOS

If that's possible, then the solution is to simply extract the public key from the server and check it against the locally stored public key...but how do Google do it?

Thanks

Chris

Note: I'm more familiar with browser to server pinning (HTTP Public Key Pinning - HPKP) rather than app to server pinning, but I presume the principal is the same. In HPKP the pinning policy is provided by the server as a HTTP header but understand this is often built into the app rather than read from the HTTP response. So read below answer with all that in mind:

Pinning is usually against the key not the cert and can be a multiple levels. So you've several choices:

  1. Reuse the same key/crt to generate a new cert. Some (rightly in my opinion.) recommend generating a new key each time you renew your cert but this is complicated when you use pinning? So does pinning encourage poor security habits like key reuse?

  2. Have several back up keys in your pinning policy and rotate them around on cert renewal discarding your oldest and adding a new one with plenty of time and updates to never be caught short. Personally I prefer to generate the key at cert renewal time rather than have some backups around which may or may have been compromised so I'm not a particular fan of this either. And how many backups should you have? Eg If you need to reissue a cert because of compromise around renewal and also mess it up? So 2? 3? 100?

  3. Pin further up. Say the first intermediate or the root CA cert. So any newly issued cert is still trusted (providing it's issued by same cert path) The downside of this is four fold: i) You still leave yourself open to miss-issued certs issued by that pinned cert (not a massive deal IMHO as you've still massively reduced your attack surface but still a concern to some people), ii) you cannot guarantee the client will use that intermediate cert as there are sometimes multiple valid paths. This second one is a much bigger deal. You'd think that providing the intermediate cert would guarantee this would be used but that's not the case (plenty of sha-1 examples of this). iii) There's no guarantee new cert will be issued by same intermediate or root (especially when technologies change like introduction of sha2), so to me this whole option is a non-starter iv) It ties you in to using same cert provider (perhaps not a big deal but I like the freedom to move). Not sure if apps support this feature natively anyway but browsers certainly do.

  4. Renew in advance and do not use the new key until policy cache expires. For example if you have one year certs and a 30 day pinning policy then you can renew after 11 months, add the new key to the policy, then wait 30 days so you can be sure everyone will have picked up new policy or at least the old policy will have expired, then switch keys and certs. Depends on a short policy and potentially wastes a portion of that though (at least 30 days in this example), unless cert provider provides cert in advance starting on day after old policy expires. For an app, if pinning policy is hard coded into it, then this might involve the length of time it takes to push out an update.

Ultimately, because certs do require renewing, I'm not a big fan of pinning. I don't think making something that is subject to periodic renewal, semi-permanent is the right answer. And there are even some talk of pre-loading pinning policies in browsers which just makes me shudder.

Pinning provides assurance that a rogue CA is not issuing certs for your domain but how likely is that really compared to the hassle of pinning? Something like Certificate Transparency - or even report only pinning may be a better answer to that problem even if they don't actually stop that attack.

Finally locally installed roots (eg for antivirus scanners or corporate proxies), bypass pinning checks (on the browser at least) which again reduces its effectiveness in my eyes.

So think carefully before using pinning and make sure you understand all the consequences.

The mozilla developer site recommends to pin the certificate of the intermediate CA that signed the server certificate.

"it is recommended to place the pin on the intermediate certificate of the CA that issued the server certificate, to ease certificates renewals and rotations."

For more information on implementing and testing public key pinning you can refer Implementing and Testing HTTP Public Key Pinning (HPKP)

Your application can store multiple certificates in its pin list. The procedure for changing the cert would then be:

  • Some time before the certificate expires, release a new version of your app with a replacement cert in the pin list, as well as the original cert
  • when the old certificate expires, replace it on the server - the app should then still work as the new cert will already be in the pin list
  • Some time after the cert expires, release a new version of your app removing the old cert

Remember your users have to update the app before the old cert expires

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM