New issue
Advanced search Search tips

Issue 803106 link

Starred by 2 users

Issue metadata

Status: WontFix
Owner: ----
Closed: Jan 2018
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: ----
Type: Bug-Security



Sign in to add a comment

Security: Push notification subscription public key can be replaced without prof of ownership (push notification hijack)

Reported by zohar.sh...@komodosec.com, Jan 17 2018

Issue description


VULNERABILITY DETAILS
When a user authorizes an app to send him push notification, a subscription is created using the app public key (so only the app owner who holds the private key can send notifications to the endpoint). However, once the initial subscription was made - any JS in the domain can now  unsubscribe the user, and re-subscribe him using a new public key - without having to prove ownership of the original private key and without requiring the user to re-authorize the notifications. 

Like so, If I example find an XSS in a website that uses notifications, I can hijack the notification mechanism:
a. I unsubscribe the user 
b. I unregister any existing service-worker
c. I re-subscribe the user using my own key (note: no user interaction is required) 
d. I register my own service worker
e. I now own the notification mechanism of the website (original website can no longer send notification, And i can send them as if they are coming from the website). 

This is very lucrative to the attacker as nor the user or the app owner know of the notification hijack, and the user has high trust in the notification as it originates from the app he trusts. 

A solution will be quite simple:
When trying to create a new subscription with a new public key, the app should first prove ownership of the original key (for example by answering a challenge that needs to be signed with the original private key). If the app cannot prove ownership of original key, a new authorization should be given by the user (perhaps a warning message to the user that the app is changing keys in a non-secure manner)


VERSION
Chrome Version: [63.0.3239.132] + [official]
Operating System: [windows 10]

REPRODUCTION CASE
I'm including a JS file that can be used to hijack notification. 
Simply input your own public key, load it into a site that contains notifications, and call the following functions:
1. unregister()
2. unsubscribe()
3. subscribeUserAgain()

I'll just note that I'm a very bad developer, so sorry for the crappy code :) 
The process however is quite easy to reproduce: Unregister current service workers, unsubscribe current notification, and subscribe again using your own key - and you have hijacked the notification machnism 

FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION
Type of crash: [tab, browser, etc.]
Crash State: [see link above: stack trace *with symbols*, registers,
exception record]
Client ID (if relevant): [see link above]

 
test.js
1.9 KB View Download
Cc: peter@chromium.org
Components: Blink>PushAPI
Interesting, thanks for the report! 

Peter, thoughts on this proposed defense-in-depth?

Comment 2 by peter@chromium.org, Jan 17 2018

Thank you for the report!

Your assessment is correct: once the user has granted permission, Web applications can create any number of subscriptions with arbitrary public keys (the applicationServerKey field) that are not authenticated against the origin.

There are a lot of subtleties about why this is the case. In no particular order:

  - A large amount of websites don't actually implement push notification functionality themselves, they defer this to an aggregation service such as OneSignal and PushCrew. Such parties send notifications on the website's behalf. Some sites even use multiple for different purposes.

  - There are various reasons why a website might want to recreate a subscription. They might want it to expire, which helps in keeping their subscription database up-to-date. They might want to rotate their own keys after a security incident, or when switching to another push aggregator.

  - Conceptually, users grant permission to "example.com"; permissions are scoped by origin. It doesn't mean anything to them if "example.com" decides to distribute notifications using an intermediary, as "unrecognizable-brand.com" and "evil-unrecognizable-brand.com" are very likely to be indistinguishable to them.

In addition, note that it's not limited to injected code *modifying* an existing subscription, it's entirely possible for the code to create a new one as well. (Although Service Worker scripts need to be hosted on the same origin, so (d) is infeasible.)

Because of the inherent multi-origin nature of how push notifications work, limiting the API to same-origin is both undesirable and unenforceable. Having a proof of possession against an arbitrary {origin, public key} pair doesn't help either, as the attacker could just implement that too.

Inherently, when an attacker can run code on behalf of a particular origin, they've got access to their storage and permissions. They could do as you describe, but also steal their cookies or get their location or take their photo if the appropriate permissions were granted. This feels as a WAI?

Comment 3 by peter@chromium.org, Jan 17 2018

Status: WontFix (was: Unconfirmed)
Let's mark it as such to get it off the triage queue -- I'd be most happy to continue discussion of course!
Hey, thanks for the quick response!

I understand and agree applications might want to have more then one key, and perhaps share this keys with other vendors, however this can still be easily verified against an original key:
a. First subscription authorisation is done with one key. This key becomes the 'Master key' 
b. registering added keys can be performed again and again, but only after proving possession of the 'Master key'  

like so, you can have as many keys as you'd like (and share keys with third parties), while maintaining control and assuring no 'malicious' keys are created. 

In case the website wants to recreate the initial subscription (for example as you said due to a key rotation) I would suggest using 'master key A' as authentication for creating the new 'Master key b', or simply re-asking the user for authorisation (otherwise the site abuses the user's trust). 

Regarding camera access and such, obviously if an attacker can run JS as an origin then he can do many things. However the key difference in this instance is the 'persistence' of the attack.
If I use an XSS to steal a cookie, for example, I can only use it as long as the session is 'alive'. If I hijack the notifications, however, the effect is 'long lasting'. I can actually use the notification system to keep directing the user to the original vulnerable url (the original XSS payload) to re-gain my access. 

While exploitation does require initial vulnerability in a site (XSS), I still think increasing the security here for the end user is pretty straight forward.

Hope you'd reconsider fixing the issue after all :)    

Comment 5 by peter@chromium.org, Jan 18 2018

What would the recovery path be if the first created subscription was created by an attacker, and thereby decided the "master key" to be their property? The real site wouldn't be able to proof ownership, of course.

There are so many valid use-cases for switching to another public key that I wouldn't consider that anything like abusing the user's trust. If we, as Chrome, or the user themselves, would be aware that certain behaviour is the effect of maliciously injected code, we could do something about that. But we're not. I don't see how a second permission prompt would help anything in that sense: users wouldn't be able to answer the "why again" question.

I agree with your persistence argument and that this definitely warrants more thought. Persistence is at the core of this API, however, and careful developers have a way to mitigate this by unsubscribing if the associated public key is unknown.

While an attacker would be able to send messages, the code used for displaying the notification (the `push` event) and handling interactions with the notification (the `notificationclick` event) cannot be forged due to the requirement of a Service Worker being hosted on the current origin. That makes a realistic attack much less probable.
Hi Peter, thanks for your answer! 

As I see it, the public key should be tied to the user authorisation as it is the only way for the user (..browser) to authenticate the server. 

Referring to the scenario of initial subscription by an attacker, I think a solution can be considered similar to SSL certificates.
A subscription could be made with an initial 'Master' key. This master key can be one of two:

1. a 'secure' master key: That is a master key pre-approved by an authority (google). The initial approval requires the developer to prove ownership of the domain for which the master key is assigned. once this key is approved - it can create further sub-keys.
If a secure master key is used, the standard 'allow notification' popup is used.

2. an 'insecure' master key: This key is similar to a self signed SSL certificate- you can create it and use if for development process, but you should not used in production deployment. If you use it, the end user would be warned (so when asking for notification authorisation - display a warning to the user that the key is insecure).

This hopefully could give the user a better security (assurance of the server's identity) while maintaining full functionality for the developer. 
I guess this would be a bit of a re-design of the mechanism but if Google decides to follow this standard I believe other browsers will soon follow. 


  

Comment 7 by peter@chromium.org, Jan 19 2018

While I appreciate the longevity of the consequences in case of XSS here, the fact that there's a simple check developers can apply—verifying the used key—and a need for additional issues in the developer's event handling code makes me believe that such solutions aren't worth it.

We associate push messaging with the Notification permission because of a number of user studies that we did. Users were unable to reason about how messages came to their device (push), but could reason about the consequences of a message (notifications). Details about *how* a developer implemented the push messaging part of such a system are completely invisible to them. Asking even an experienced user to choose between keys we consider "secure" or "insecure" won't work.

Replicating SSL certificates means, beyond various other issues, introducing gatekeepers in a system that we worked hard to keep entirely open. It far exceeds the scope of what the feature is trying to achieve and increases adoption costs unproportionally to the gained benefits.

There's a very fine balance to walk between usability and security. I think that we're on the right side of the line here, and that there are no changes warranted.

Project Member

Comment 8 by sheriffbot@chromium.org, Apr 26 2018

Labels: -Restrict-View-SecurityTeam allpublic
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot

Sign in to add a comment