Cross-Site Leaks (XS-Leaks)
Cross-site leaks (auch als XS-Leaks bezeichnet) sind eine Angriffsklasse, bei der die Seite eines Angreifers Informationen über die Zielseite oder die Beziehung des Benutzers zur Zielseite ableiten kann, indem Web-Plattform-APIs genutzt werden, die es Seiten ermöglichen, miteinander zu interagieren. Die durchgesickerten Informationen könnten beispielsweise Folgendes umfassen:
- Ob der Benutzer die Zielseite besucht hat.
- Ob der Benutzer bei der Zielseite angemeldet ist.
- Was die Benutzer-ID auf der Seite ist.
- Was der Benutzer kürzlich auf der Seite gesucht hat.
Dies mag als ein viel weniger schädliches Problem erscheinen als zum Beispiel ein Cross-Site Scripting Angriff, kann aber dennoch schwerwiegende Konsequenzen für die Benutzer haben. Zum Beispiel:
- Ein Benutzer könnte Konten auf Websites haben, die er nicht öffentlich machen möchte. Wenn diese Informationen einem Angreifer zugänglich werden, könnten sie zu Erpressung oder Vergeltungsmaßnahmen einer repressiven Regierung führen (zum Beispiel gegen einen Benutzer, der Informationen über spezifische medizinische Verfahren sucht).
- Zu wissen, dass ein Benutzer ein Konto auf einer Seite hat, insbesondere wenn dessen Benutzer-ID ermittelt werden kann, kann einen anschließenden Phishing-Angriff viel überzeugender machen.
Anders als bei anderen Angriffen wie XSS oder Clickjacking sind Cross-Site Leaks keine einzelne Technik. Stattdessen handelt es sich um einen Begriff für eine ganze Klasse von Angriffen, die Schwächen in der Art und Weise ausnutzen, wie Browser Websites voneinander isolieren.
In diesem Leitfaden werden wir nicht versuchen, jeden Cross-Site Leak Angriff und jede Verteidigung zu beschreiben. Stattdessen beginnen wir damit, ein paar Beispielangriffe zu beschreiben, dann die gemeinsamen zugrunde liegenden Schwächen darzulegen, die sie ermöglichen, und schließlich einige allgemeine Abwehrmaßnahmen zu beschreiben, die gegen viele bekannte Angriffe wirken können.
Beispielhafte Cross-Site Leaks
In diesem Abschnitt werden wir drei verschiedene Cross-Site Leaks beschreiben, um eine Vorstellung davon zu geben, wie sie funktionieren.
- Leaking page existence using error events: In diesem Angriff kann ein Angreifer durch die Einbindung als Ressourcen und das Abhören von
error
undload
Ereignissen feststellen, ob bestimmte Endpunkte auf der Zielseite HTTP-Fehlercodes zurückgeben. Wenn bestimmte Seiten nur für angemeldete Benutzer verfügbar sind, kann der Angreifer feststellen, ob der Benutzer bei der Zielseite angemeldet ist. - Frame counting using window references: In diesem Angriff erhält der Angreifer eine Referenz auf ein
window
Objekt, das eine Seite der Zielseite beherbergt, zum Beispiel als Rückgabewert eines Aufrufs vonwindow.open()
. Der Angreifer kann dann die Anzahl der<iframe>
Elemente auf der Zielseite bestimmen, was wiederum möglicherweise offenbart, ob der Benutzer beim Ziel angemeldet ist. - Leaking redirects with a CSP: In diesem Angriff hat die Seite des Angreifers eine Content Security Policy, die nur das Laden einer bestimmten Seite der Zielseite erlaubt, und versucht dann, diese Seite zu laden. Wenn der Seitenladevorgang blockiert wird, weiß der Angreifer, dass das Ziel die Anfrage umgeleitet hat. Diese Umleitung kann anzeigen, ob der Benutzer angemeldet war oder nicht, je nachdem, wie die Seite funktioniert.
Alle drei Angriffe werden auf die gleiche Weise ausgeführt: Der Angreifer erstellt eine Seite, die den Angriff umsetzt, und überzeugt dann den Benutzer, die Seite zu besuchen, zum Beispiel indem er eine E-Mail sendet oder einen Beitrag teilt, der den Link enthält. Wenn der Benutzer die Seite besucht, wird der Angriff automatisch ausgeführt.
Im Rest dieses Abschnitts werden wir diese drei Angriffe etwas detaillierter beschreiben, um Ihnen ein konkretes Gefühl dafür zu geben, wie sie funktionieren. Obwohl die drei Angriffe ganz unterschiedliche Teile der Web-Plattform anvisieren, haben sie eine gemeinsame Ursache: das Ausmaß, in dem der Browser es Websites ermöglicht, sich gegenseitig durch Mechanismen wie das Einrahmen, das Laden von Unterressourcen oder das Öffnen neuer Fenster zu verbinden und zu interagieren.
Hinweis: Für ein umfassenderes Verzeichnis von Cross-Site Leaks, siehe das XS-Leaks Wiki und das OWASP Cross-site Leaks Cheat Sheet.
Leaking page existence using error events
Bei diesem Angriff testet der Angreifer, ob bestimmte Seiten auf der Zielseite geladen werden können, indem überprüft wird, ob Versuche, sie als Ressourcen einzubinden, einen Fehler erzeugen. Wenn diese Seiten nur für angemeldete Benutzer verfügbar sind, könnte ein Angreifer feststellen, ob ein Benutzer angemeldet ist.
Der Angriff basiert auf der Fähigkeit einer Website, eine Ressource von einer anderen Seite zu laden, zum Beispiel durch Setzen des src
Attributs eines <script>
Elements auf die URL der Ressource:
const script = document.createElement("script");
script.src = "https://example.org/admin";
document.head.appendChild(script);
Dies führt zu einer HTTP-Anfrage an die https://example.org/
Website. Wenn die Anfrage Cookies enthält, die die Seite zur Identifikation von Benutzern verwendet, und die angeforderte Seite nur für angemeldete Benutzer verfügbar ist, dann verrät der Erfolg oder das Scheitern der Anfrage, ob der Benutzer angemeldet ist.
Wenn die Anfrage fehlschlägt, zum Beispiel weil der Server einen HTTP 404
Statuscode zurückgibt, erzeugt das Element ein error
Ereignis. Wenn die Anfrage erfolgreich ist, erzeugt das Element ein load
Ereignis. Durch das Abhören dieser Ereignisse kann der Angreifer herausfinden, ob der Benutzer angemeldet ist.
const url = "https://example.org/admin";
const script = document.createElement("script");
script.addEventListener("load", (e) => {
console.log(`${url} exists`);
});
script.addEventListener("error", (e) => {
console.log(`${url} does not exist`);
});
script.src = url;
document.head.appendChild(script);
Ein Angreifer könnte sogar in der Lage sein, die Benutzer-ID zu entdecken, indem er iterativ versucht, Seiten zu laden, um zu sehen, ob Seiten wie https://example.org/users/my_username
existieren.
Frame counting using window references
Bei einem Frame-Counting-Angriff findet der Angreifer die Anzahl der derzeit auf der Zielseite geladenen Frames heraus. Das wiederum gibt Aufschluss über den Zustand der Zielseite, wodurch der Angreifer beispielsweise erfahren kann, ob der Benutzer derzeit auf der Seite angemeldet ist.
Wenn eine Angreifer-Seite eine Referenz auf ein Window
Objekt erhält, das die Zielseite enthält, kann der Angreifer die Anzahl der Frames auf der Zielseite ermitteln, indem er die window.length
Eigenschaft liest.
Der Angreifer kann ein Window
Objekt erhalten, indem er window.open()
aufruft:
const target = window.open("https://example.org");
const frames = target.length;
Alternativ kann der Angreifer die Zielseite in einem <iframe>
einbetten und die contentWindow
Eigenschaft des Frames abrufen:
<iframe src="https://example.org"></iframe>
const target = document.querySelector("iframe").contentWindow;
const frames = target.length;
Leaking redirects with a CSP
Auf einigen Websites leitet der Server eine Anfrage basierend darauf um, ob der Benutzer angemeldet ist (oder einen besonderen Status auf der Seite hat) oder nicht. Stellen Sie sich beispielsweise eine Seite vor, die Administratoren eine Seite unter https://admin.example.org/
anzeigt. Wenn der Benutzer nicht angemeldet ist und diese Seite anfordert, könnte der Server ihn zu https://login.example.org/
umleiten. Das bedeutet, dass, wenn ein Angreifer feststellen könnte, ob ein Versuch, https://admin.example.org/
zu laden, zu einer Umleitung führt, er weiß, ob der Benutzer ein Administrator auf der Seite ist.
In dem hier beschriebenen Angriff nutzt der Angreifer die Content Security Policy (CSP), um zu erkennen, ob eine cross-site Anfrage umgeleitet wurde.
-
Zuerst erstellen sie eine Seite, die einer CSP unterliegt, die nur
<iframe>
Elemente erlaubt, Inhalte vonhttps://admin.example.org/
zu enthalten. -
Als Nächstes fügen sie auf der Seite einen Ereignis-Listener hinzu, der auf das
securitypolicyviolation
Ereignis hört. -
Schließlich erstellen sie ein
<iframe>
Element und setzen dessensrc
Attribut aufhttps://admin.example.org/
.
<!DOCTYPE html>
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="frame-src https://admin.example.org/" />
</head>
<body>
<script>
document.addEventListener("securitypolicyviolation", () => {
console.log("Page was redirected");
});
const frame = document.createElement("iframe");
document.body.appendChild(frame);
frame.src = "https://admin.example.org/";
</script>
</body>
</html>
- Wenn der Benutzer als Administrator angemeldet ist, wird das
<iframe>
geladen und der Browser löst keinsecuritypolicyviolation
aus. - Wenn der Benutzer nicht als Administrator angemeldet ist, leitet der Server zu
https://login.example.org/
um. Da diese URL von der CSP des Angreifers nicht erlaubt ist, blockiert der Browser das<iframe>
und löst dassecuritypolicyviolation
Ereignis aus, worauf der Ereignishandler des Angreifers ausgeführt wird.
Beachten Sie, dass dieser Angriff auch funktioniert, wenn die Zielseite das Einbetten durch einen Mechanismus wie frame-ancestors
verbietet.
Abwehrmaßnahmen gegen Cross-Site Leaks
Cross-Site Leaks nutzen Mechanismen in der Web-Plattform aus, die es Websites ermöglichen, miteinander zu interagieren. Entsprechend bestehen die Abwehrmaßnahmen gegen Cross-Site Leaks normalerweise darin, die Ziel-Website von potenziellen Angreifern zu isolieren, indem diese Cross-Site Interaktionen deaktiviert oder kontrolliert werden.
Da Cross-Site Leaks auf viele verschiedene Arten funktionieren können, gibt es keine einzige Abwehrmaßnahme, die gegen alle wirkt. Es gibt jedoch mehrere Praktiken, die gegen viele von ihnen wirken, und wir werden sie hier zusammenfassen.
Fetch Metadata
Fetch Metadata ist der Begriff für eine Sammlung von HTTP-Anforderungsheadern, die Informationen über den Kontext einer HTTP-Anfrage bereitstellen, einschließlich:
Sec-Fetch-Site
: Ob die Anfrage gleichherkunft, gleiche Seite oder übergreifend ist.Sec-Fetch-Mode
: Dermode
der Anfrage.Sec-Fetch-User
: Ob die Anfrage eine vom Benutzer initiierte Navigation ist.Sec-Fetch-Dest
: Dasdestination
der Anfrage.
Fetch Metadata Header sind kein eigenes Abwehrmechanismus, aber sie ermöglichen einem Server, eine Richtlinie zu implementieren, die Anfragen ablehnt, die in Cross-Site Leaks sowie anderen Angriffen wie Cross-Site Request Forgery (CSRF) verwendet werden.
Zum Beispiel hängt der Angriff Leaking page existence using error events davon ab, dass der Angreifer übergreifende Anfragen stellen kann, um Seiten der Zielseite als Ressourcen zu laden:
// Attempt to load a page in the target as a resource
const script = document.createElement("script");
script.src = "https://example.org/admin";
document.head.appendChild(script);
Ein Server kann Fetch Metadata verwenden, um diese Anfragen abzulehnen, wie im folgenden Express Code:
function isAllowed(req) {
// Allow same-origin, same-site, and user-initiated requests
const secFetchSite = req.headers["sec-fetch-site"];
if (
secFetchSite === "same-origin" ||
secFetchSite === "same-site" ||
secFetchSite === "none"
) {
return true;
}
// Allow cross-site navigations, such as clicking links
const secFetchMode = req.headers["sec-fetch-mode"];
if (secFetchMode === "navigate" && req.method === "GET") {
return true;
}
// Deny everything else
return false;
}
app.get("/admin", (req, res) => {
res.setHeader("Vary", "sec-fetch-site, sec-fetch-mode");
if (isAllowed(req)) {
// Respond with the admin page if the user is admin
getAdminPage(req, res);
} else {
res.status(404).send("Not found.");
}
});
Da die Anfrage des Angreifers übergreifend und keine Navigation ist, gibt dieser Server immer einen Fehler zurück, unabhängig davon, ob der Benutzer angemeldet ist oder nicht.
Beachten Sie, dass wir auch den Vary
Antwort-Header senden. Dies stellt sicher, dass, wenn die Antwort zwischengespeichert wird, die zwischengespeicherte Antwort nur Anfragen mit denselben Werten für die Fetch Metadata Header erhält, die wir verwenden.
Eine solche Richtlinie wird als Resource Isolation Policy bezeichnet. Um mehr darüber zu erfahren, wie man Isolationsrichtlinien mit Fetch Metadata implementiert, siehe Protect your resources from web attacks with Fetch Metadata und Isolation Policies.
SameSite Cookies
Das SameSite
Cookie-Attribut bestimmt, ob das Cookie in Anfragen gesendet wird, die von einer anderen Seite stammen.
Der Wert Lax
von SameSite
bedeutet, dass übergreifende Anfragen das Cookie nur dann enthalten, wenn die Anfrage eine Top-Level-Navigation ist (was im Wesentlichen bedeutet, dass sich der Wert in der Adressleiste des Browsers zur Zielseite ändert) und eine sichere Methode verwendet (insbesondere ausschließt dies POST
Anfragen).
Dies kann gegen einige Cross-Site Leaks schützen. Zum Beispiel hängt der Angriff Leaking page existence using error events davon ab, dass der Angreifer übergreifende Ressourcenanfragen stellt, die die Sitzungscookies des Benutzers enthalten. Wenn SameSite
auf Lax
im Sitzungscookie des Benutzers eingestellt wird, würde dieser Angriff verhindert, da das Cookie nicht in die Anfrage des Angreifers aufgenommen würde und keine Seiten, die eine Anmeldung erfordern, jemals zurückgegeben würden.
Im Allgemeinen sollte SameSite
als Maßnahme der Verteidigung in der Tiefe behandelt und zusätzlich zu einer expliziteren Isolationsrichtlinie wie einer auf Fetch Metadata basierenden eingesetzt werden.
Einbettungsschutz
Viele Cross-Site Leaks verlassen sich darauf, dass die angreifende Seite das Ziel als <iframe>
einbetten kann. Dies ist beispielsweise eine Methode, die ein Angreifer verwenden kann, um eine Referenz auf das window
der Zielseite zu erhalten, um einen Frame-Counting Angriff zu ermöglichen.
Das bedeutet, dass es eine gute Praxis ist, zu verhindern, dass eine Seite eingebettet werden kann, es sei denn, Sie müssen das Einbetten ausdrücklich ermöglichen. Und wenn das Einbetten erlaubt sein muss, schränken Sie es so weit wie möglich ein.
Hier gibt es zwei relevante Werkzeuge:
- Die
frame-ancestors
Direktive in einer Content Security Policy. - Der
X-Frame-Options
Antwort-Header.
Die frame-ancestors
Direktive ist ein Ersatz für X-Frame-Options
. Obwohl Browserunterstützung für frame-ancestors
sehr gut ist, unterstützen einige sehr alte Browser, insbesondere Internet Explorer, frame-ancestors
nicht.
Wenn frame-ancestors
und X-Frame-Options
beide gesetzt sind, ignorieren Browser, die frame-ancestors
unterstützen, X-Frame-Options
. Das bedeutet, dass es keinen Grund gibt, X-Frame-Options
nicht zusätzlich zu frame-ancestors
zu setzen und so das Einbetten auch in Browsern zu verhindern, die frame-ancestors
nicht unterstützen.
Cross-Origin Opener Policy (COOP)
Wie wir beim Frame-Counting Angriff gesehen haben, gibt es eine weitere Methode, um eine Referenz auf das window
der Zielseite zu erhalten, nämlich als Rückgabewert eines Aufrufs von window.open()
:
const target = window.open("https://example.com");
Der Cross-Origin-Opener-Policy
Antwort-Header bestimmt, ob ein Dokument in derselben Browsing-Context-Gruppe wie das Dokument geladen wird, das es geöffnet hat.
Wenn Ihr Server diesen Header sendet und auf einen anderen Wert als den Standard "unsafe-none"
setzt, dann wird, wenn ein Dokument von einem anderen Ursprung versucht, Ihre Seite mit window.open()
zu öffnen, Ihre Seite in einer anderen Browsing-Context-Gruppe geladen. Unter anderem bedeutet dies, dass der Opener keine Referenz auf das window
Objekt Ihrer Seite erhält und daher nicht in der Lage sein wird, es in einem Frame-Counting-Angriff zu verwenden.
Zusammenfassende Checkliste der Abwehrmaßnahmen
Wie wir gesehen haben, umfassen Cross-Site Leaks eine Reihe von Angriffen, die sich auf unterschiedliche Teile der Web-Plattform konzentrieren: Eine einzige Abwehrmaßnahme funktioniert gegen keinen von ihnen. Tatsächlich haben einige Leaks, wie dasjenige, das CSP ausnutzt, um Umleitungen zu leaken, noch keine Abwehrmaßnahmen.
In diesem Leitfaden haben wir einige Abwehrmaßnahmen skizziert, die helfen, Ihre Seite von potenziellen Angreifern zu isolieren, und wir empfehlen, alle davon zu implementieren:
- Verwenden Sie Fetch Metadata, um eine Ressourcenisolationsrichtlinie umzusetzen.
- Setzen Sie das
SameSite
Attribut für Sitzungscookies aufStrict
, wenn möglich, oderLax
, wenn nötig. - Verwenden Sie die
frame-ancestors
CSP Direktive und denX-Frame-Options
Antwort-Header, um zu verhindern, dass Ihre Seite eingebettet wird, oder um zu kontrollieren, welche Seiten Ihre Seite einbetten können. - Senden Sie den
Cross-Origin-Opener-Policy
Antwort-Header, um zu verhindern, dass andere Seiten auf Ihrwindow
globales Objekt zugreifen können.
Siehe auch
- XS-Leaks Wiki (xsleaks.dev)
- Cross-site leaks Cheat Sheet (OWASP)