Comment by raizer88

Comment by raizer88 a day ago

16 replies

Since we're on the topic of certificates, my app (1M+ logins per day) uses certificate pinning with a cert that lasts for one year, because otherwise it would be a nightmare to roll the cert multiple times in production. But what would be the "modern" way to do smart and automated certificate pinning, now that short-lived certs are becoming the trend?

nickf a day ago

Don't. Don't pin to public certificates. You're binding your app to third-party infrastructure beyond your control. Things change, and often. Note that pinning to a root or intermediate seems 'sensible' - but it isn't. Roots are going to start changing every couple of years. Issuing/intermediate CAs will be down to 6 months, and may even need to be randomised so when you request a new cert, there's no guarantee it'll be from the same CA as before.

Don't pin to certs you don't control.

  • arccy 19 hours ago

    This, have you thought about what happens when your CA needs to revoke your certificate because of some issue? can you even realistically re-pin before it's revoked (hours-days)?

gucci-on-fleek a day ago

The certificates will expire, but (as far as I'm aware), you're still allowed to use the same private key for multiple certificates, so as long as you pin to the public key instead of to the certificate itself, you should be fine.

The real modern way to do certificate pinning is to not do certificate pinning at all, but I'm sure that you've already heard this countless times before. An alternative option would be to run your own private CA, generate a new public/private keypair every 45 days, and generate certificates with that public key using both your private CA and Let's Encrypt, and then pin your private CA instead of the leaf certificates.

  • toast0 a day ago

    > The certificates will expire, but (as far as I'm aware), you're still allowed to use the same private key for multiple certificates, so as long as you pin to the public key instead of to the certificate itself, you should be fine.

    It's allowed, but the intent of short cert expiration is to also have short private key lifetimes, so that point in time key compromises have time limited forgery potential. If the same key is used for a long period, someone who got the key once can download your public certificate and use that with the key they have.

    > The real modern way to do certificate pinning is to not do certificate pinning at all, but I'm sure that you've already heard this countless times before. An alternative option would be to run your own private CA, generate a new public/private keypair every 45 days, and generate certificates with that public key using both your private CA and Let's Encrypt, and then pin your private CA instead of the leaf certificates.

    The tricky thing here is you need to serve your private CA signed cert to pinned clients and a PKI cert to browser clients. If you want cert pinning for browsers (which afaik, is very limited availability), you should pick at least two CAs that you are pretty sure will continue to issue you certs and won't be delisted; bonus if you're also confident they won't issue certs for your domains without your explicit consent.

    I would also recommend two private CAs, if you're doing private CAs. Store them physically separate, so if one is compromised or becomes unavailable, you can use the other.

    • nickf 14 hours ago

      I still think 'don't pin' is the best advice, but absolutely it should never be done to public CAs. I agree with your point about different endpoints, but maybe one endpoint for pinned apps, separate to your browser-based sites/endpoints.

throwaway89201 a day ago

I think the suggestion of pinning the public key and keeping the same private key across certs is the best option. But if you don't want that, perhaps this is a (high complexity, high fragility) alternative:

- Make sure your app checks that enough trusted embedded Signed Certificate Timestamps are present in the certificate (web browsers and the iOS and Android frameworks already do this by default).

- Disallow your app to trust certificates that are more recently requested than N hours. This might be hard to do.

- Set up monitoring to the certificate transparency logs to verify that no bad actor has obtained a certificate (and make sure you are always able to revoke them within N hours).

- Make sure you always have fresh keys with certificates in cold storage older than N hours, because you can't immediately use newly obtained certificates

jeroenhd a day ago

Pinning the intermediate CA should work. Alternatively, calculate the cost of updating the cert pinning mechanism if it's custom and compare it to paid, 1 year certificates (though those will go away eventually too).

On the other hand, if you're using an app specific server, there's no need for you to use public certificates. A self-generated one with a five or ten year validity will pin just as nicely. That breaks if you need web browsers or third parties to talk to the same API, of course.

  • phasmantistes 20 hours ago

    Please don't suggest pinning a publicly-trusted intermediate. The CA may change which intermediate they're using at any time for any reason with no warning, and then the app which pinned that intermediate is hosed.

    • jeroenhd 18 hours ago

      It depends what intermediate you pin, but the CA can also choose to change the root certificate they use at any time like Let's Encrypt did in 2024 when the CA that signed their cross signed certificate stood to expire. Plus, depending on where you get your certificates from, the reseller certificate may already be an intermediate rather than its own root.

      You should probably pin the highest certificate in the chain that's going to stay current for as long as possible. Or, if the goal is just "I don't want people snooping around in my app's traffic" rather than "I want to protect against a rogue CA being used to hijack my customers' traffic", reuse the private key in the CSR and pin that, it'll get the job done.

  • nickf a day ago

    It'll be tough when ICAs rotate every 5/6 months and may even randomise.

    • jeroenhd 18 hours ago

      You can prepare CSRs with new public keys years in advance. It'll take some certbot/ACME scripting to use them instead of aurogenerating new ones on the fly, but that way you can pin your future certificates. Add pins as you prepare new CSRs and drop them as the certificates expire, and depending on the size of the list you choose you should be good for months or years without app updates.

      Plus, if you do any key pinning, you'd probably do well to also pin a backup public key you haven't used in case your CA/infra collapses and you quickly need to redo your HTTPS setup.

      • nickf 18 hours ago

        You can, but it’s still dangerous. You don’t have control over if those certs are revoked or keys blocklisted.

        It’s best to simply not use public certs for pinning, if you really must do it.

jrjfjgkrj a day ago

your app would download the new certificate from an endpoint which returns the new certificate signed with the old one that you currently pin?