Ressourcen mit Fetch Metadata vor Webangriffen schützen

CSRF-, XSSI- und plattformübergreifende Datenlecks verhindern

Lukas Weichselbaum
Lukas Weichselbaum

Warum sollten Sie Ihre Webressourcen isolieren?

Viele Webanwendungen sind anfällig für Cross-Origin-Angriffe wie Cross-Site-Request-Forgery (CSRF), Cross-Site-Script-Inclusion (XSSI), Timing-Angriffe, Cross-Origin-Datenleckas oder spekulative ausführungsseitige Seitenkanalattacken (Spectre).

Mit den Anfrageheadern Fetch Metadata können Sie einen starken Defense-in-Depth-Mechanismus – eine Ressourcenisolierungsrichtlinie – implementieren, um Ihre Anwendung vor diesen gängigen plattformübergreifenden Angriffen zu schützen.

Es ist üblich, dass Ressourcen, die von einer bestimmten Webanwendung bereitgestellt werden, nur von der Anwendung selbst und nicht von anderen Websites geladen werden. In solchen Fällen ist die Implementierung einer Ressourcenisolierungsrichtlinie, die auf Anfrageheadern für das Abrufen von Metadaten basiert, mit wenig Aufwand verbunden und schützt gleichzeitig die Anwendung vor websiteübergreifenden Angriffen.

Browserkompatibilität

Anfrageheader für das Abrufen von Metadaten werden von allen modernen Browser-Engines unterstützt.

Unterstützte Browser

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 90.
  • Safari: 16.4.

Quelle

Hintergrund

Viele websiteübergreifende Angriffe sind möglich, weil das Web standardmäßig offen ist und sich Ihr Anwendungsserver nicht einfach vor der Kommunikation schützen kann, die von externen Anwendungen ausgeht. Ein typischer Angriff zwischen verschiedenen Ursprüngen ist die Cross-Site Request Forgery (CSRF), bei der ein Angreifer einen Nutzer auf eine von ihm kontrollierte Website lockt und dann ein Formular an den Server sendet, auf dem der Nutzer angemeldet ist. Da der Server nicht erkennen kann, ob die Anfrage von einer anderen Domain stammt (websiteübergreifend), und der Browser automatisch Cookies an websiteübergreifende Anfragen anhängt, führt der Server die vom Angreifer angeforderte Aktion im Namen des Nutzers aus.

Andere Website-Angriffe wie Cross-Site-Script-Inclusion (XSSI) oder Cross-Origin-Informationslecks ähneln CSRF und beruhen auf dem Laden von Ressourcen aus einer Opferanwendung in ein vom Angreifer kontrolliertes Dokument und dem Auslaufen von Informationen über die Opferanwendungen. Da Anwendungen vertrauenswürdige Anfragen nicht leicht von nicht vertrauenswürdigen unterscheiden können, können sie schädlichen websiteübergreifenden Traffic nicht ablehnen.

Jetzt neu: „Metadaten abrufen“

Header für Fetch Metadata-Anfragen sind eine neue Sicherheitsfunktion der Webplattform, die Servern dabei helfen soll, sich vor Cross-Origin-Angriffen zu schützen. Durch die Bereitstellung von Informationen zum Kontext einer HTTP-Anfrage in einer Reihe von Sec-Fetch-*-Headern können die antwortenden Server Sicherheitsrichtlinien anwenden, bevor die Anfrage verarbeitet wird. So können Entwickler entscheiden, ob sie eine Anfrage annehmen oder ablehnen möchten, je nachdem, wie sie gestellt wurde und in welchem Kontext sie verwendet wird. So ist es möglich, nur auf legitime Anfragen zu reagieren, die von ihrer eigenen Anwendung stammen.

Same-Origin
Anfragen von Websites, die von Ihrem eigenen Server bereitgestellt werden (gleicher Ursprung), funktionieren weiterhin. Eine Abrufanfrage von https://website.de für die Ressource https://website.de/foo.json in JavaScript führt dazu, dass der Browser den HTTP-Anfrageheader „Sec Fetch-Site: same-origin“ sendet.
Websiteübergreifend
Maliziöse websiteübergreifende Anfragen können vom Server aufgrund des zusätzlichen Kontexts in der HTTP-Anfrage abgelehnt werden, der durch Sec-Fetch-*-Header bereitgestellt wird. Ein Bild auf https://evil.example, bei dem das src-Attribut eines img-Elements auf „https://site.example/foo.json“ festgelegt ist, führt dazu, dass der Browser den HTTP-Anfrageheader „Sec-Fetch-Site: cross-site“ sendet.

Sec-Fetch-Site

Unterstützte Browser

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 90.
  • Safari: 16.4.

Quelle

Sec-Fetch-Site teilt dem Server mit, von welcher Website die Anfrage gesendet wurde. Der Browser legt diesen Wert auf einen der folgenden Werte fest:

  • same-origin, wenn die Anfrage von Ihrer eigenen Anwendung gesendet wurde (z.B. site.example)
  • same-site, wenn die Anfrage von einer Subdomain Ihrer Website stammt (z.B. bar.site.example)
  • none, wenn die Anfrage explizit durch die Interaktion eines Nutzers mit dem User-Agent verursacht wurde (z.B. Klicken auf ein Lesezeichen)
  • cross-site, wenn die Anfrage von einer anderen Website gesendet wurde (z.B. evil.example)

Sec-Fetch-Mode

Unterstützte Browser

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 90.
  • Safari: 16.4.

Quelle

Sec-Fetch-Mode gibt den Modus der Anfrage an. Dies entspricht ungefähr dem Anfragetyp und ermöglicht es Ihnen, Ressourcenladungen von Navigationsanfragen zu unterscheiden. Ein Ziel von navigate gibt beispielsweise eine Navigationsanfrage auf oberster Ebene an, während no-cors Ressourcenanfragen wie das Laden eines Bildes angibt.

Sec-Fetch-Dest

Unterstützte Browser

  • Chrome: 80.
  • Edge: 80.
  • Firefox: 90.
  • Safari: 16.4.

Quelle

Sec-Fetch-Dest gibt das Ziel einer Anfrage an (z.B. wenn ein script- oder img-Tag dazu geführt hat, dass eine Ressource vom Browser angefordert wurde).

Fetch Metadata zum Schutz vor plattformübergreifenden Angriffen verwenden

Die zusätzlichen Informationen, die diese Anfrageheader liefern, sind recht einfach. Mit dem zusätzlichen Kontext können Sie jedoch mit nur wenigen Codezeilen eine leistungsstarke Sicherheitslogik auf der Serverseite erstellen, die auch als Ressourcenisolierungsrichtlinie bezeichnet wird.

Richtlinie zur Ressourcenisolierung implementieren

Mit einer Richtlinie zur Ressourcenisolierung wird verhindert, dass Ihre Ressourcen von externen Websites angefordert werden. Durch das Blockieren solcher Zugriffe werden häufige Cross-Site-Web-Sicherheitslücken wie CSRF, XSSI, Timing-Angriffe und Cross-Origin-Informationslecks reduziert. Diese Richtlinie kann für alle Endpunkte Ihrer Anwendung aktiviert werden und erlaubt alle Ressourcenanfragen, die von Ihrer eigenen Anwendung stammen, sowie direkte Navigationen (über eine HTTP-GET-Anfrage). Für Endpunkte, die in einem websiteübergreifenden Kontext geladen werden sollen (z.B. Endpunkte, die mit CORS geladen werden), kann diese Logik deaktiviert werden.

Schritt 1: Anfragen von Browsern zulassen, die keine Metadaten abrufen

Da nicht alle Browser „Fetch Metadata“ unterstützen, müssen Sie Anfragen zulassen, die keine Sec-Fetch-*-Header setzen. Prüfen Sie dazu, ob sec-fetch-site vorhanden ist.

if not req['sec-fetch-site']:
  return True  # Allow this request

Schritt 2: Anfragen innerhalb der Website und vom Browser initiierte Anfragen zulassen

Alle Anfragen, die nicht aus einem ursprungsübergreifenden Kontext stammen (z. B. evil.example), werden zugelassen. Dazu gehören insbesondere Anfragen, die:

  • Sie stammen aus Ihrer eigenen Anwendung (z.B. eine Anfrage vom selben Ursprung, bei der site.example-Anfragen site.example/foo.json immer zulässig sind).
  • Sie stammen aus Ihren Subdomains.
  • Sie werden durch die Interaktion eines Nutzers mit dem User-Agent explizit verursacht (z. B. durch direkte Navigation oder Klicken auf ein Lesezeichen).
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
  return True  # Allow this request

Schritt 3: Einfache Navigation auf oberster Ebene und Iframing zulassen

Damit Ihre Website weiterhin von anderen Websites verlinkt werden kann, müssen Sie die einfache (HTTP GET) Navigation auf oberster Ebene zulassen.

if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
  # <object> and <embed> send navigation requests, which we disallow.
  and req['sec-fetch-dest'] not in ('object', 'embed'):
    return True  # Allow this request

Schritt 4: Endpunkte deaktivieren, die für websiteübergreifende Zugriffe gedacht sind (optional)

In einigen Fällen stellt Ihre Anwendung möglicherweise Ressourcen bereit, die websiteübergreifend geladen werden sollen. Diese Ressourcen müssen pro Pfad oder pro Endpunkt ausgenommen werden. Beispiele für solche Endpunkte:

  • Endpunkte, auf die über mehrere Ursprünge hinweg zugegriffen werden soll: Wenn Ihre Anwendung Endpunkte bereitstellt, für die CORS aktiviert ist, müssen Sie die Ressourcenisolierung für diese Endpunkte explizit deaktivieren, damit weiterhin websiteübergreifende Anfragen an diese Endpunkte möglich sind.
  • Öffentliche Ressourcen (z. B. Bilder, Stile): Auch öffentliche und nicht authentifizierte Ressourcen, die plattformübergreifend von anderen Websites geladen werden können, können ausgenommen werden.
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
  return True

Schritt 5: Alle anderen websiteübergreifenden Anfragen ablehnen, die nicht auf Navigation zurückzuführen sind

Alle anderen websiteübergreifenden Anfragen werden von dieser Richtlinie zur Ressourcenisolierung abgelehnt und Ihre Anwendung wird so vor gängigen websiteübergreifenden Angriffen geschützt.

Beispiel:Der folgende Code veranschaulicht eine vollständige Implementierung einer robusten Richtlinie zur Ressourcenisolierung auf dem Server oder als Middleware, um potenziell schädliche websiteübergreifende Ressourcenanfragen abzulehnen und gleichzeitig einfache Navigationsanfragen zuzulassen:

# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs
def allow_request(req):
  # Allow requests from browsers which don't send Fetch Metadata
  if not req['sec-fetch-site']:
    return True

  # Allow same-site and browser-initiated requests
  if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
    return True

  # Allow simple top-level navigations except <object> and <embed>
  if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
    and req['sec-fetch-dest'] not in ('object', 'embed'):
      return True

  # [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.
  if req.path in ('/my_CORS_endpoint', '/favicon.png'):
    return True

  # Reject all other requests that are cross-site and not navigational
  return False

Richtlinie zur Ressourcenisolierung bereitstellen

  1. Installieren Sie ein Modul wie das Code-Snippet oben, um das Verhalten Ihrer Website zu protokollieren und zu überwachen und dafür zu sorgen, dass die Einschränkungen keinen legitimen Traffic beeinträchtigen.
  2. Beheben Sie potenzielle Verstöße, indem Sie legitime plattformübergreifende Endpunkte ausnehmen.
  3. Erzwingen Sie die Richtlinie, indem Sie nicht konforme Anfragen ablehnen.

Richtlinienverstöße erkennen und beheben

Wir empfehlen, die Richtlinie zuerst im Berichtsmodus in Ihrem serverseitigen Code zu aktivieren, um unerwünschte Auswirkungen zu vermeiden. Alternativ können Sie diese Logik in Middleware oder in einem Reverse-Proxy implementieren, der alle Verstöße protokolliert, die bei der Anwendung Ihrer Richtlinie auf Produktionszugriffe auftreten.

Aus unserer Erfahrung mit der Einführung einer Richtlinie zur Ressourcenisolierung für das Abrufen von Metadaten bei Google sind die meisten Anwendungen standardmäßig mit einer solchen Richtlinie kompatibel und es sind nur selten Ausnahmen für Endpunkte erforderlich, um websiteübergreifenden Traffic zuzulassen.

Ressourcenisolationsrichtlinie erzwingen

Nachdem Sie überprüft haben, dass sich Ihre Richtlinie nicht auf legitimen Produktionstraffic auswirkt, können Sie Einschränkungen erzwingen. So wird sichergestellt, dass andere Websites Ihre Ressourcen nicht anfordern können, und Ihre Nutzer werden vor websiteübergreifenden Angriffen geschützt.

Weitere Informationen