maplibre / maplibre-gl-js

MapLibre GL JS - Interactive vector tile maps in the browser
https://maplibre.org/maplibre-gl-js/docs/
Other
6.57k stars 703 forks source link

Security: `Actor` should be protected against XSS attacks in `postMessage` / `onmessage` #3239

Closed ghost closed 10 months ago

ghost commented 1 year ago

This is a theoretical situation only - there's no PoC and the described attack might not work in practice on maplibre. maplibre is not less secure than many other npm packages / libs - these (targeted) attacks are unlikely, but they'll gain significance as maplibre is being used in more products.


User Story

A user opens multiple tabs.

One of them is using maplibre in a context where security should be expected:

Another tab contains a hostile website which aims to extract as much data as possible from the other tab that use maplibre (including potential credentials, personal information or similar).

That data gets stolen (and potentially abused).

Rationale

The (probably) affected code is (among other locations) here:

https://github.com/maplibre/maplibre-gl-js/blob/fbdb32dc439f41c37d1a6dc2d695f10446b72016/src/util/actor.ts#L88 https://github.com/maplibre/maplibre-gl-js/blob/fbdb32dc439f41c37d1a6dc2d695f10446b72016/src/util/actor.ts#L232

There are many XSS attacks on postMessage / onMessage which is used in the maplibre Actor to communicate with the web-workers.

Examples of attacks and words of caution:

It's fairly easy to add additional security measures. Recently, a similar PR for mapbox has taken steps to secure their Actor implementation.

Impact

There are many attacks and even if there's no practical PoC, the fact that this might be exploitable should be taken seriously until proven otherwise. With maplibre being widely used (including large companies like Meta, Microsoft and others), someone will eventually try to attack it and if there is a vulnerability, it will be found and exploited.

Notes

On OSM Slack ( https://osmus.slack.com/archives/C01G3D28DAB/p1697724774588149 ), I proposed to generate random UUID when maplibre is loaded, which is then attached to each message from/to the webworkers, so they know it's from the map (initial communication of the UUID could happen in the worker source). Thereby there'd be a trusted channel as no code in another window/tab could know the UUID to communicate with the worker.

I'm unable to find any thoughts on this UUID technique. Most documentation seems to only check the origin (which I consider to be flawed, especially as the origin might not be known ahead of time or there might be multiple pages on the same origin). So, my proposal with the UUID for the trusted channel might also have flaws.

I also noticed that the throttled_invoker uses https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API which might be intended for this case (I'm not sure). However, even the standard for that uses an untrusted postMessage: https://html.spec.whatwg.org/multipage/web-messaging.html#introduction-13 (which needs to be protected somehow to build a chain of trust).

Someone with a better understanding of postMessage and onmessage / XSS attacks and web standards in this area is probably needed to assess the situation and propose a proven method to secure maplibre.

ghost commented 1 year ago

I've tried to do some XSS on our own website (not maplibre) now to learn about this and it's not as trivial as it initially seemed. I'm unable to even send a message when creating the target window via JS (not sure why yet). It also seems to be impossible (?) to get the window object of another tab (without opening it from JS), so this would "only" affect iframes (not an issue for our website, but probably an issue for maplibre, but not in the cases I mentioned)

I might try again in the future.

HarelM commented 11 months ago

I've opened a PR to address this, although I'm not sure there is an attack vector here, and you can bypass it with setting a the relevant origin in the message itself... IDK, better than nothing I guess. The only way to attack I think is sending a message to the worker to process some data in a different way, this might cause a map refresh and in some cases you might be able to show something different than expected on the map due to the data you sent to the worker, maybe, but I'm not sure you can really cause something to execute or send data to an attacker...

HarelM commented 10 months ago

Fixed by #3329 which was merged as part of #3233