w3c / push-api

Push API
https://w3c.github.io/push-api/
Other
145 stars 40 forks source link

Some questions about VAPID and encrypted messages #278

Closed floatingstone closed 7 years ago

floatingstone commented 7 years ago

1. Should all of the subscribe requests's applicationServerKey be stored in the push service database? When we subscribe a user, we pass in an applicationServerKey. This key is passed to the push service. Many forgery subscribe requests with different applicationServerKey can cause the push service to be attacked.

2. VAPID replay attacks. The authentication scheme of the VAPID is vulnerable to replay attacks if an attacker can acquire a valid JWT. So besides the "exp" value, what else can we do to reduce this risk?

3. When application server wants to push encrypted messages: a) Does the push service need to check whether the request body has been replaced or not? b) Or just pass the encrypted messages to target subscriber?

beverloo commented 7 years ago

Hi @floatingstone, thank you for the questions! Please do note that there is a repository for VAPID (https://github.com/webpush-wg/webpush-vapid) as well, but it's relevant enough so I'll answer your questions in this issue.

  1. Should all of the subscribe requests's applicationServerKey be stored in the push service database?

The application server definitely has to remember which key was used, if it has several, as it will need to proof possession of the associated private key by signing the JWT token.

The push service needs to store this key if it decides to support Subscription Restrictions (see section 4). Otherwise the k parameter in the Authorization header will do.

Note that, to my knowledge, all public push services that support VAPID also support Subscription Restrictions.

  1. VAPID replay attacks.

Indeed: this is detailed in section 5. Using near-immediate, say a couple of seconds if your server accurately keeps time, expiration times is the best way to counter this.

  1. When application server wants to push encrypted messages: a) Does the push service need to check whether the request body has been replaced or not? b) Or just pass the encrypted messages to target subscriber?

The push service doesn't have the ability to decrypt the message, so the intention is for it to pass on the entire payload, unmodified, to the client.

floatingstone commented 7 years ago

@beverloo, Thank you so much for your reply, :)

The push service needs to store this key if it decides to support Subscription Restrictions (see section 4). Otherwise the k parameter in the Authorization header will do.

Should push service check the validation of this key before decide to store it ? If don't, following code may let the push service store a lot of useless information.

while (true) {
  const newRandomStr = <random string...>;

  const subscribeOptions = {
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(
      newRandomStr
    )
  };

  registration.pushManager.subscribe(subscribeOptions);
}
martinthomson commented 7 years ago

A push service can validate the keys, but that is up to them.

beverloo commented 7 years ago

The Push API does say that applicationServerKey has to be a valid P-256 point, so the while the user agent may do some verification, the push service may not. We (Google w/ Firebase Cloud Messaging) do validate.

martinthomson commented 7 years ago

I think that Firefox validates the point. The push service basically has to if it is verifying a signature.

(In other words, I was originally wrong.)

floatingstone commented 7 years ago

What about the following scenario? How does the push service store the applicationServerKey?

while(true) {
  // construct a subscribe request using a fake "vapid" (changes every time);
  // send the request to the push service;
}

Request format:

POST /subscribe/ HTTP/1.1 Host: push.example.net Content-Type: application/webpush-options+json;charset=utf-8 Content-Length:

{ "vapid": ".......fake infomation......." }

beverloo commented 7 years ago

When talking in context of the Push API, because a Service Worker can only have a single subscription that'd have to be a subscribe-then-unsubscribe loop.

In either scenario, yes, that would create any number of subscriptions with different applicationServerKey values. It's not defined how the push service stores this, but conceptually it's just a piece of metadata it stores with the subscription.

floatingstone commented 7 years ago

In either scenario, yes, that would create any number of subscriptions with different applicationServerKey values. It's not defined how the push service stores this, but conceptually it's just a piece of metadata it stores with the subscription.

This creates a lot of subscriptions that is not actually used. I think, for hackers, this could be a chance to attack the push service.

beverloo commented 7 years ago

Yes, this is an operational risk of running a push service.

beverloo commented 7 years ago

Let me close this - please reply or open a new issue if there's anything else! :)