Sicheres Hosting von Nutzerdaten in modernen Webanwendungen

David Dworken
David Dworken

Viele Webanwendungen müssen von Nutzern gesteuerte Inhalte anzeigen. Das kann so einfach sein wie das Bereitstellen von von Nutzern hochgeladenen Bildern (z. B. Profilfotos) oder so komplex wie das Rendern von von Nutzern gesteuertem HTML (z. B. ein Webentwicklungstutorial). Das war schon immer schwierig, sicher zu tun. Deshalb haben wir daran gearbeitet, einfache, aber sichere Lösungen zu finden, die auf die meisten Arten von Webanwendungen angewendet werden können.

Klassische Lösungen zum Isolieren nicht vertrauenswürdiger Inhalte

Die klassische Lösung zum sicheren Bereitstellen von von Nutzern gesteuerten Inhalten besteht darin, sogenannte Sandbox-Domains zu verwenden. Die Grundidee ist, dass Sie alle nicht vertrauenswürdigen Inhalte auf exampleusercontent.com bereitstellen können, wenn die Hauptdomain Ihrer Anwendung example.com ist. Da diese beiden Domains websiteübergreifend sind, können sich böswillige Inhalte auf exampleusercontent.com nicht auf example.com auswirken. Mit diesem Ansatz können alle Arten von nicht vertrauenswürdigen Inhalten, einschließlich Bildern, Downloads und HTML, sicher bereitgestellt werden. Auch wenn es nicht so aussieht, als wäre das für Bilder oder Downloads erforderlich, hilft es, Risiken durch Content Sniffing zu vermeiden, insbesondere in älteren Browsern. Sandbox-Domains werden in der gesamten Branche häufig verwendet und haben sich lange bewährt. Sie haben jedoch zwei große Nachteile:

  • Anwendungen müssen den Zugriff auf Inhalte häufig auf einen einzelnen Nutzer beschränken. Dazu müssen Authentifizierung und Autorisierung implementiert werden. Da Sandbox-Domains Cookies bewusst nicht mit der Hauptdomain der Anwendung teilen, ist das sehr schwierig sicher zu tun. Zur Unterstützung der Authentifizierung müssen Websites entweder auf Capability-URLs zurückgreifen oder separate Authentifizierungscookies für die Sandbox-Domain festlegen. Diese zweite Methode ist im modernen Web besonders problematisch, da viele Browser websiteübergreifende Cookies standardmäßig einschränken.
  • Nutzerinhalte sind zwar von der Hauptwebsite isoliert, aber nicht von anderen Nutzerinhalten. Dadurch besteht das Risiko, dass böswillige Nutzerinhalte andere Daten auf der Sandbox-Domain angreifen (z. B. durch Lesen von Daten mit derselben Quelle).

Sandbox-Domains tragen auch dazu bei, Phishing-Risiken zu mindern, da Ressourcen klar auf einer isolierten Domain segmentiert sind.

Moderne Lösungen zum Bereitstellen von Nutzerinhalten

Im Laufe der Zeit hat sich das Web weiterentwickelt und es gibt jetzt einfachere und sicherere Möglichkeiten, nicht vertrauenswürdige Inhalte bereitzustellen. Es gibt viele verschiedene Ansätze. Wir stellen zwei Lösungen vor, die wir bei Google verwenden.

Ansatz 1: Bereitstellen von inaktiven Nutzerinhalten

Wenn eine Website nur inaktive Nutzerinhalte bereitstellen muss (d. h. Inhalte, die kein HTML oder JavaScript sind, z. B. Bilder und Downloads), kann das jetzt sicher ohne isolierte Sandbox-Domain erfolgen. Dazu sind zwei wichtige Schritte erforderlich:

  • Legen Sie den Content-Type Header immer auf einen bekannten MIME-Typ fest, der von allen Browsern unterstützt wird und keine aktiven Inhalte enthält. Im Zweifelsfall ist application/octet-stream eine sichere Wahl.
  • Legen Sie außerdem immer die Antwortheader so fest, dass der Browser die Antwort vollständig isoliert.
Antwortheader Purpose

X-Content-Type-Options: nosniff

Verhindert Content Sniffing

Content-Disposition: attachment; filename="download"

Löst einen Download aus, anstatt zu rendern

Content-Security-Policy: sandbox

Führt den Inhalt in einer Sandbox aus, als ob er auf einer separaten Domain bereitgestellt würde

Content-Security-Policy: default-src ‘none'

Deaktiviert die JavaScript-Ausführung (und das Einbeziehen von Unterressourcen)

Cross-Origin-Resource-Policy: same-site

Verhindert, dass die Seite websiteübergreifend eingebunden wird

Diese Kombination von Headern sorgt dafür, dass die Antwort nur als Unterressource von Ihrer Anwendung geladen oder vom Nutzer als Datei heruntergeladen werden kann. Außerdem bieten die Header durch den CSP-Sandbox-Header und die Einschränkung default-src mehrere Sicherheitsebenen gegen Browserfehler. Insgesamt bietet die beschriebene Einrichtung ein hohes Maß an Sicherheit, dass Antworten, die auf diese Weise bereitgestellt werden, nicht zu Injection- oder Isolationsschwachstellen führen können.

Defense in Depth

Die vorgeschlagene Lösung bietet zwar einen im Allgemeinen ausreichenden Schutz vor XSS, es gibt jedoch eine Reihe zusätzlicher Maßnahmen zur Härtung, mit denen Sie zusätzliche Sicherheitsebenen hinzufügen können:

  • Legen Sie einen X-Content-Security-Policy: sandbox-Header für die Kompatibilität mit IE11 fest.
  • Legen Sie einen Content-Security-Policy: frame-ancestors 'none'-Header fest, um zu verhindern, dass der Endpunkt eingebettet wird.
  • Führen Sie Nutzerinhalte in einer Sandbox auf einer isolierten Subdomain aus:
    • Bereitstellen von Nutzerinhalten auf einer isolierten Subdomain (z.B. verwendet Google Domains wie product.usercontent.google.com).
    • Legen Sie Cross-Origin-Opener-Policy: same-origin und Cross-Origin-Embedder-Policy: require-corp fest, um die websiteübergreifende Isolierung zu aktivieren.

Ansatz 2: Bereitstellen von aktiven Nutzerinhalten

Aktive Inhalte (z. B. HTML- oder SVG-Bilder) können auch ohne die Schwachstellen des klassischen Sandbox-Domain-Ansatzes sicher bereitgestellt werden.

Die einfachste Option besteht darin, den Header Content-Security-Policy: sandbox zu verwenden, um den Browser anzuweisen, die Antwort zu isolieren. Nicht alle Webbrowser implementieren die Prozessisolierung für Sandbox-Dokumente. Durch laufende Verbesserungen der Browserprozessmodelle wird die Trennung von Sandbox-Inhalten von einbettenden Anwendungen jedoch wahrscheinlich verbessert. Wenn SpectreJS und Renderer-Kompromittierungsangriffe nicht in Ihrem Bedrohungsmodell enthalten sind, ist die Verwendung von CSP-Sandbox wahrscheinlich eine ausreichende Lösung. Wir bei Google haben eine Lösung entwickelt, mit der nicht vertrauenswürdige aktive Inhalte vollständig isoliert werden können, indem das Konzept der Sandbox-Domains modernisiert wird. Die Grundidee ist:

  • Erstellen Sie eine neue Sandbox-Domain, die der Liste der öffentlichen Suffixe hinzugefügt wird. Wenn Sie beispielsweise exampleusercontent.com zur PSL hinzufügen, können Sie sicherstellen, dass foo.exampleusercontent.com und bar.exampleusercontent.com websiteübergreifend und somit vollständig voneinander isoliert sind.
  • URLs, die mit *.exampleusercontent.com/shim übereinstimmen, werden alle an eine statische Shim-Datei weitergeleitet. Diese Shim-Datei enthält ein kurzes HTML- und JavaScript-Snippet, das auf den message-Ereignishandler wartet und alle empfangenen Inhalte rendert.
  • Dazu erstellt das Produkt entweder ein iFrame oder ein Dialogfeld für $RANDOM_VALUE.exampleusercontent.com/shim und sendet die nicht vertrauenswürdigen Inhalte mit postMessage an den Shim, um sie zu rendern.
  • Die gerenderten Inhalte werden in einen Blob umgewandelt und in einem Sandbox-iFrame gerendert.

Im Vergleich zum klassischen Sandbox-Domain-Ansatz wird so sichergestellt, dass alle Inhalte vollständig auf einer eindeutigen Website isoliert sind. Da die Hauptanwendung die Daten abruft, die gerendert werden sollen, sind Capability-URLs nicht mehr erforderlich.

Fazit

Mit diesen beiden Lösungen können Sie von klassischen Sandbox-Domains wie googleusercontent.com zu sichereren Lösungen migrieren, die mit der Blockierung von Drittanbieter-Cookies kompatibel sind. Wir bei Google haben bereits viele Produkte auf diese Lösungen umgestellt und planen für das nächste Jahr weitere Migrationen.