cloudevents / spec

CloudEvents Specification
https://cloudevents.io
Apache License 2.0
5.02k stars 581 forks source link

HTTP webhook signature-based proof-of-origin #703

Closed alexec closed 3 years ago

alexec commented 3 years ago

Currently the web hook spec mandates an Authorization header. However, many common web hooks use signature-based header. This is typically a header that contains a hashed digest of a secret and the request payload. This acts as proof of origin. Unfortunately, this is in now way standardised. Github, Githlab, BitBucket, Stripe all use different headers and algos meaning you must implement X and X as many bugs and security issues. Nor does it mandate any of these systems abide by best security practices, use the best crypto, future proof themselves (i.e. how does one migrate Github from RSA to ECC - impossible?).

Because signature-based proof-of-origin is common, CloudEvents can and should standardise this.

Some ideas:

References::

RichiCoder1 commented 3 years ago

There's a pretty long running spec draft for request signatures in the IETF, but it's focused on specifically HTTP Request Signing: https://www.ietf.org/id/draft-ietf-httpbis-message-signatures-00.html

That said, it could also provide some inspiration here.

clemensv commented 3 years ago

The Authorization header is a generic mechanism defined in https://tools.ietf.org/html/rfc7235#section-4.2

There are no restrictions to what you can put into that field, it only needs to work for both client and server. The upside of using "Authorization" is that RFC7235 prescribes that the header must not be cached, which custom schemes do not.

The point of the WebHooks spec is to constrain the HTTP binding further in order to provide broader interop. Accommodating arbitrary, proprietary AuthNZ schemes would be contra-productive.

At the same time, I don't see us being in the security business. OAuth2 bearer tokens with TLS seems to be where the security folks have largely landed for securing these kinds of interactions and that's why we lean on that.

alexec commented 3 years ago

I'm not sure about this "authorization" and "signature" are semantically different. A message signature would not, in itself, be an authorization. And there is clearly a use case for signatures instead of authorization, otherwise it would not be more common that authorization.

That said, I would expect the RFC to cover all signature use cases and CloudEvents could just point to that.

manuelstein commented 3 years ago

Regarding https://www.ietf.org/id/draft-ietf-httpbis-message-signatures-00.html, I'll take a wild guess and say it will expire in 10 days, but that's my personal view. This has been going on for a while https://datatracker.ietf.org/doc/draft-ietf-httpbis-message-signatures/ and there was a similar attempt in 2011 to sign content https://datatracker.ietf.org/doc/draft-burke-content-signature/.

In Github webhooks, IIUC X-Hub-Signature serves two things: authentication (by the use of the correct secret) and message integrity. I don't see how the receiver identifies the principal, is it maybe in User-Agent? In Gitlab webhook, the X-Gitlab-Token can carry any token specified by the user, but is unfortunately carried in a proprietary header. Neither use the Authorization: Bearer token. AFAICS both Gitlab/hub use of a secret is optional.

Not sure what the use case is. You can encode a OAuth Bearer token as a query parameter in the URL. That HTTPS URL can be used with both Gitlab and Github, so they would be sending webhooks conforming with the specified OAuth2 method.

If the use case here is to forward their payloads as CloudEvents data, an intermediary could augment the request with ce-* headers, but of course, the method can only authorize the request with the intermediary. The SSL channel confidentiality doesn't hold all the way to the consumer, so IIUC we can't have authorization with CE-webhooks across (untrusted) intermediaries. Is that the concern @alexec?

An idea for Github webhooks would be to retain X-Hub-Signature and verify it at the consumer for end-to-end authorization. Gitlab's secret token would be exposed to the intermediary, so that should be a trusted entity.

sdatspun2 commented 3 years ago

@alexec Let me know how we can work on this. For Fintechs and banks, this would be an obvious requirement.

alexec commented 3 years ago

For FinTech and banking, I think you should look at the OpenBanking specs:

https://standards.openbanking.org.uk/

Disclaimer: I was one of the dozens of architects on this, so you can expect it to be extremely thorough.

both Gitlab/hub use of a secret is optional.

I did not know that. I suggest we do not support minimal (zero?) security use cases.

For the highest security level (which Github webhook is not) I would expect an API to mandate mutual TLS.

I would be suspicious of recommending query parameters for any security-related aspect. These often appear in plain text in web server logs. This is much worse than just logging user passwords in plain-text. I would not expect it to be allowed at a security audit.

Both the above are high-security use cases. Many webhook use cases will be low security.

By default for CloudEvents, can we be high-security, please?

It may be you don't even want to support signatures?

sdatspun2 commented 3 years ago

@alexec Glad to know you contributed to OB. Can you point how you have handled webhook security (esp. message integrity) in OB world? I know for APIs JWS is used.

duglin commented 3 years ago

On 10/15 call, Anish said he would try to write-up a PR or some guidance to consider.

sdatspun2 commented 3 years ago

Let's make sure we are not turning away API developers who want to use cloudevent schema for events delivered using webhooks. Many API developers, esp. on fintech side would want to know how to do this. To verify integrity of data, some properties of the envelope such as datacontenttype , dataschema, subject, time, type and source would be needed.

Here are some examples what API developers are doing on their own re webhook signature for proprietary event schema.

https://developer.goto.com/guides/HowTos/08_HOW_webhooks/ https://stripe.com/docs/webhooks/signatures https://developers.onfido.com/guide/manual-webhook-signature-verification https://developers.samsara.com/docs/webhooks#webhook-signatures https://documentation.tradier.com/advisor-api/webhooks/securing-webhooks https://www.twilio.com/docs/usage/webhooks/webhooks-security https://developer.squareup.com/docs/webhooks-api/validate-notifications https://developer.intuit.com/app/developer/qbo/docs/develop/webhooks/managing-webhooks-notifications#validating-the-notification

alexec commented 3 years ago

I don't think I'd recommend JWS (maybe compressed JWE) due to (a) the cookie size issue they have there's always one use with many groups who cookie is >4096KB) and (b) JWS is transparent plain-text (JWEs are opaque) that cannot be revoked.

I think it is interesting that you non-goal security. As security is fundamental to any transport or provider - no implementer can avoid it. I'm assuming that does not mean you eschew security perse, just that you do not either recommend or mandate anything.

However, this does put implementors in an uncomfortable position. For each and every single provider you wish to integrate with you must perform a bespoke integration. Problems:

Basically, this makes signature-based webhooks very costly and very risky.

With that is mind:

jayadeba commented 3 years ago

@alexec what is the issue if JWS is used for signature. Thats the standard. Also when you want to sign a Cloudevent a JWS payload goes inside the "data" field of cloud event in structured mode and the datacontenttype will have application/jwt as the media type.

Why a separate signature header required at all?

duglin commented 3 years ago

Given we merged: https://github.com/cloudevents/spec/pull/712 can we close this?