Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSC2970: Remove pusher path requirement #2970

Open
wants to merge 4 commits into
base: old_master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions proposals/2970-remove-pusher-path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# MSC2970: Remove pusher path requirement
richvdh marked this conversation as resolved.
Show resolved Hide resolved

Recently Synapse was updated to enforce the specified restriction that the URI
for HTTP pushers have a path component of `/_matrix/push/v1/notify`
([synapse#8865](https://github.com/matrix-org/synapse/pull/8865)).

Prior to this change, the ability to use arbitrary paths for pushers had been
found useful for various applications. Examples include:

* Projects such as [matrix-gotify](https://gitlab.com/Sorunome/matrix-gotify)
offer a mechanism for push notifications which is independent from Google's
FCM or Apple's push system. These setups, however, typically have a URL
specific to a device, which is incompatible with the requirement for a fixed
path.

* Push notifications could be sent directly to the IPv6 address of a phone, if
it is known. However, depending on implementation, it might be difficult to
arrange to receive pushes on a specific path.

In general, having a path requirement for the pushers basically forces app
developers to implement and host matrix-specific gateways, instead of just
being able to push general json blobs directly to devices. The removal of the
pusher path requirement would *greatly* increase flexibility here.

## Proposal

The requirements for the `url` parameter for [`POST
/_matrix/client/r0/pushers/set`](https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-pushers-set)
are relaxed. In particular:

* The path need no longer be `/_matrix/push/v1/notify`.
* The requirement that the URL be `https` is extended to allow `http`, but
strongly recommend `https`.

Some additional constraints are added to ensure compatibility between implementations:

* The URL MUST contain a valid host, with an optional port. IP literal
addresses are permitted, in accordance with [RFC3986
3.2.2](https://tools.ietf.org/html/rfc3986#section-3.2.2).
* The URL must NOT contain a fragment (ie, it may not contain the character
`#`). (It *may* contain a query-string.)
* The URL must NOT include a "userinfo" section (ie, the host may not be
preceded by a `user@` specification).
* The URL must consist solely of ASCII characters. (Unicode hostnames should
be Punycode-encoded. Non-ASCII bytes in the path should be percent-encoded.)
* The URL may not exceed 8000 characters in length.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8000 was picked fairly randomly based on https://tools.ietf.org/html/rfc7230#section-3.1.1.



### Versioning

One reason that the constraint on paths was introduced was to allow the future
introduction of new, incompatible, push formats - with the intention that the
homeserver pick the format to be used based on the path in the URL of the
pusher.

It is proposed instead that this could be done by changing the `kind` of
pusher: for example by setting it to `httpv2`.

## Potential issues

The removal of the path constraint potentially makes it easier to construct
HTTP magnification/DoS attacks, using the homeserver as a proxy.

It could also make it easier to construct attacks against internal
infrastructure (ie, SSRF attacks). This is somewhat lessened by the fact that
an attacker has no way to read the response to such a request, but blind
SSRF attacks are still possible.

Although these are valid concerns, we note that Matrix Pushes are not
significantly different in this respect to many other "webhook" systems (for
example, Github's
[webhooks](https://docs.github.com/en/developers/webhooks-and-events/about-webhooks)
system and [AWS
SNS](https://docs.aws.amazon.com/sns/latest/dg/sns-http-https-endpoint-as-subscriber.html)),
which have no such constraint.

Rather, we propose that these attacks be mitigated by other controls such as
the following -- all of which are important anti-abuse controls regardless of
whether the URL path is restricted:

* All outgoing HTTP requests from the Homeserver should be subject to an IP
address blacklist, so that the server administrator can prevent access to
internal resources.

* We could require that the push endpoint respond to an empty `ping` request -
and in particular that it must respond at the time that the pusher is
configured. This would significantly reduce the scope for abuse by directing
pushes to inappropriate endpoints.

However, it is considered out-of-scope for this MSC.
Comment on lines +85 to +90
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this, I think it would be quite a beneficial addition. However, it would be a backwards-incompatible change to the pusher API (currently, there is no way to do a "test notification" other than by making up an event of some form), and generally needs a bit more time to write into an MSC than I have time for right now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to suggest something like this, though I thought about requiring either that the pusher URL ends with /_matrix/push/v1/notify or that it responds to GET requests with a predetermined response that proves it's expecting pushes.

Agreed this should be out-of-scope for this MSC.

Copy link
Member

@clokep clokep Apr 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed above this could be done pretty easily by adding an httpv2 pusher type? I guess this would require clients to know the types that a server supports though, which they might not currently.

Also -- would this be compatible with the proposed projects above (matrix-gotify, etc.)?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkasak Another way to verify the pusher URL is how JMAP does it like a phone number verification code.

when a subscription is created, the JMAP server immediately sends a PushVerification object to that URL

NOT make any further requests to the URL until the client receives the push and updates the subscription with the correct verification code


* Outgoing requests must be subject to rate-limiting, to prevent individual
users creating large volumes of requests. Additionally, there should be a
per-user limit on the total number of pushers.

* If a push endpoint does not give a valid response at all (for example, over a
period of 7 days), the pusher should be disabled.

## Alternatives

### Partial constraints on URI paths

An alternative approach would be to allow more flexibility in the push endpoint
path, whilst still imposing some constraints. For example, we might say that
the path must start with, or end with, `/_matrix/push/v1/notify`. Such an
appproach might help to mitigate SSRF attacks whilst still allowing some
flexibility for alternative implementations.

We consider that requiring that the path *start* with `/_matrix/etc` offers too
little flexibility for some implementations, and that requiring that it *end*
with `/_matrix/etc` offers little protection. For example, an attakcer might
configure a pusher with an endpoint
`https://example.com/app%3Fx%3D/_matrix/etc`, which then appears as a request
to `/app` with a query-string.

In short, we consider the benefits of such an approach are minor.

### Leave the HTTPS requirement in place

Arguably the relaxation of the requirement that the push endpoint be HTTPS is
orthogonal, but we consider this a good time to reconsider that requirement.

In short, there are various deployment strategies - in particular, where a push
gateway is known to be hosted on the same infrastructure as the homeserver -
where the requirement for HTTPS is unnecessarily onerous. In most scenarios,
HTTPS is preferable for obvious reasons, but We don't consider it the job of
the pusher API to enforce this.
Comment on lines +126 to +127
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
HTTPS is preferable for obvious reasons, but We don't consider it the job of
the pusher API to enforce this.
HTTPS is preferable for obvious reasons, but we don't consider it the job of
the pusher API to enforce this.


### Disallow query-strings

We could also disallow query-strings in the URL. However, these are also useful
in certain applications (in particular, they are sometimes used for addtional
authorization).

## Security considerations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to @clokep's comment (here) there's an added concern of being able to register pushers which point at random web services. This not only can point at internal infrastructure, but also a random webserver out in the wild. A handshake process may be in order.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the same as @clokep's comment, or somehow different?

@clokep wrote:

targeting arbitrary URLs.

@turt2live wrote

being able to register pushers which point at random web services

in any case, IMHO: this is no different from any other service that provides webhooks: there is no requirement on the target path for a Github event notifications, for example.

Pivoting into internal infrastructure should be handled with IP blacklists etc (an effective IP blacklist is already required for URL previews.)

Other services that provide webhooks don't require a handshake, and I'm unconvinced that we need one. It sounds like an an annoyance for people to set up.

Concerns over traffic amplification should be handled with rate-limiting (and making sure that pushers that don't get the correct response get disabled), which is orthogonal to the URL path.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the same as @clokep's comment, or somehow different?

@clokep wrote:

targeting arbitrary URLs.

My intention from that blurb is pretty much the same as what @turt2live wrote.

in any case, IMHO: this is no different from any other service that provides webhooks: there is no requirement on the target path for a Github event notifications, for example.

Yes, that's true. We should at least document that this does have security implications to it.

(P.S. Sorry for forgetting to use a thread!)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I think the security implications of sending less restricted HTTP requests from the homeserver are important to note but worth the minor risk.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope I've now described the security considerations in question.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to me! 👍


As described above, this change could make DoS and SSRF attacks easier, and it
is important that good countermeasures be put in place before such a change.

## Unstable prefix

We do not anticipate making a public release of the changes proposed here
before the MSC is accepted; an unstable prefix is therefore not required.