logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git

Can-we-talk-about-client-side-certs.md (5764B)


  1. ---
  2. date: 2020-06-12
  3. layout: post
  4. title: Can we talk about client-side certificates?
  5. categories: [tls, security, oauth]
  6. ---
  7. I'm working on improving the means by which API users authenticate with the
  8. SourceHut API. Today, I was reading [RFC 6749][6749] (OAuth2) for this purpose,
  9. and it got me thinking about the original OAuth spec. I recalled vaguely that it
  10. had the API clients actually *sign* every request, and... [yep, indeed it
  11. does][5849]. This also got me thinking: what else signs requests? TLS!
  12. [6749]: https://tools.ietf.org/html/rfc6749
  13. [5849]: https://tools.ietf.org/html/rfc5849
  14. OAuth is very complicated. The RFC is 76 pages long, the separate bearer token
  15. RFC (6750) is another 18, and no one has ever read either of them. Add JSON Web
  16. Tokens (RFC 7519, 30 pages), too. The process is complicated and everyone
  17. implements it themselves — a sure way to make mistakes in a
  18. security-critical component. Not all of the data is authenticated, no
  19. cryptography is involved at any step, and it's easy for either party to end up
  20. in an unexpected state. The server has to deal with problems of revocation and
  21. generating a secure token itself. Have you ever met anyone who feels positively
  22. about OAuth?
  23. Now, take a seat. Have a cup of coffee. I want to talk about client-side
  24. certificates. Why didn't they take off? Let's sketch up a hypothetical TLS-based
  25. protocol as an alternative to OAuth. Picture the following...
  26. 1. You, an API client developer, generate a certificate authority and
  27. intermediate, and you upload your CA certificate to the Service Provider as
  28. part of your registration as a user agent.
  29. 2. When you want a user to authorize you to access their account, you generate a
  30. certificate for them, and redirect them to the Service Provider's
  31. authorization page with a <abbr title="Certificate Signing Request">CSR</abbr>
  32. in tow. Your certificate includes, among other things, the list of authorized
  33. scopes for which you want to be granted access. It is already signed with
  34. your client CA key, or one of its intermediates.
  35. 3. The client reviews the desired access, and consents. They are redirected back
  36. to your API client application, along with the signed certificate.
  37. 4. Use this client-side certificate to authenticate your API requests. Hooray!
  38. Several advantages to this approach occur to me.
  39. - You get strong encryption and authentication guarantees for free.
  40. - TLS is basically the single most ironclad, battle-tested security mechanism on
  41. the internet, and mature implementations are available for every platform.
  42. Everyone implements OAuth themselves, and often poorly.
  43. - Client-side certificates are stateless. They contain all of the information
  44. necessary to prove that the client is entitled to access.
  45. - If you handle SSL termination with nginx, haproxy, etc, you can reject
  46. unauthorized requests before your application backend ever even sees them.
  47. - The service provider can untrust the client's CA in a single revocation, if
  48. they are malicious or lose their private keys.
  49. - The API client and service provider are both always certain that the process
  50. was deliberately initiated by the API client. No weird state tokens to carry
  51. through the process like OAuth uses!
  52. - Lots of free features: any metadata you like, built-in expirations, API
  53. clients can self-organize into intermediates at their discretion, and so on.
  54. - Security-concious end users can toggle a flag in their account which would, as
  55. part of the consent process, ask them to sign the API client's certificate
  56. themselves, before the signed certificate is returned to the API client. Then
  57. any API request authorized for that user's account has to be signed by the API
  58. client, the service provider, *and* the user to be valid.
  59. Here's another example: say your organization has several services, each of
  60. which interacts with a subset of Acme Co's API on behalf of their users. Your
  61. organization generates a single root CA, and signs up for Acme Co's API with it.
  62. Then you issue intermediate CAs to each of your services, which are *only*
  63. allowed to issue CSRs for the subset of scopes they require. If any service is
  64. compromised, it can't be used to get more access than it already had, and you
  65. can revoke just that one intermediate without affecting the rest.
  66. Even some famous downsides, such as <abbr title="Certificate Revocation
  67. Lists">CRLs</abbr> and <abbr title="Online Certificate Status
  68. Protocol">OCSP</abbr>, are mitigated here, because the system is much more
  69. centralized. You control all of the endpoints which will be validating
  70. certificates, you can just distribute revocations directly to them as soon as
  71. they come in.
  72. The advantages are clearly numerous. Let's wrap it up in a cute, Google-able
  73. name, write some nice tooling and helper libraries for it, and ship it!
  74. Or, maybe not. I have a nagging feeling that I'm missing something here. It
  75. doesn't seem right that such an obvious solution would have been left on the
  76. table, by everyone, for decades. Maybe it's just that the whole certificate
  77. signing dance has left a bad taste in everyone's mouth &mdash; many of us have
  78. not-so-fond memories of futzing around with the awful OpenSSL CLI to generate a
  79. CSR. But, there's no reason why we couldn't do it better, and more streamlined,
  80. if we had the motivation to.
  81. There are also more use-cases for client-side certificates that seem rather
  82. compelling, such as an alternative to user passwords. Web browser support for
  83. client-side certificates totally sucks, but that is a solvable problem.
  84. For the record, I have no intention of using this approach for the SourceHut
  85. API. This thought simply occurred to me, and I want to hear what you think. Why
  86. aren't we using client-side certificates?