Sicheres Hosting von Nutzerdaten in modernen Webanwendungen

David Dworken
David Dworken

Viele Webanwendungen müssen vom Nutzer gesteuerte Inhalte anzeigen. Das kann so einfach wie das Bereitstellen von von Nutzern hochgeladenen Bildern (z. B. Profilbilder) oder so komplex wie das Rendern von von Nutzern gesteuertem HTML (z. B. ein Tutorial zur Webentwicklung) sein. Das war immer schwierig, daher haben wir nach einfachen, aber sicheren Lösungen gesucht, die auf die meisten Arten von Webanwendungen angewendet werden können.

Die klassische Lösung für die sichere Bereitstellung von von Nutzern gesteuerten Inhalten sind sogenannte Sandbox-Domains. Wenn die Hauptdomain Ihrer Anwendung example.com ist, können Sie alle nicht vertrauenswürdigen Inhalte auf exampleusercontent.com bereitstellen. Da diese beiden Domains websiteübergreifend sind, können schädliche Inhalte auf exampleusercontent.com keine Auswirkungen auf example.com haben.
Mit diesem Ansatz können alle Arten nicht vertrauenswürdiger Inhalte sicher bereitgestellt werden, einschließlich Bildern, Downloads und HTML. Auch wenn es für Bilder oder Downloads nicht unbedingt erforderlich erscheint, hilft dies, Risiken durch Content-Sniffing zu vermeiden, insbesondere in älteren Browsern.
Sandbox-Domains werden in der Branche weithin verwendet und funktionieren seit langem gut. Es gibt jedoch zwei große Nachteile:

  • Bei Anwendungen muss der Inhaltszugriff häufig auf einen einzelnen Nutzer beschränkt werden. Dazu müssen Authentifizierung und Autorisierung implementiert werden. Da in Sandbox-Domains bewusst keine Cookies mit der Hauptdomain der Anwendung geteilt werden, ist dies nur sehr schwer auf sichere Weise möglich. Um die Authentifizierung zu unterstützen, müssen Websites entweder Funktions-URLs verwenden oder separate Authentifizierungs-Cookies 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 getrennt, aber nicht von anderen Nutzerinhalten. Dadurch besteht das Risiko, dass schädliche Nutzerinhalte andere Daten in der Sandbox-Domain angreifen (z. B. durch Lesen von Daten desselben Ursprungs).

Außerdem tragen Sandbox-Domains dazu bei, Phishing-Risiken zu minimieren, da Ressourcen klar in einer isolierten Domain segmentiert sind.

Moderne Lösungen für die Bereitstellung 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 Ihnen daher zwei Lösungen vor, die derzeit bei Google weit verbreitet sind.

Methode 1: Inhalte inaktiver Nutzer bereitstellen

Wenn auf einer Website nur Inhalte für inaktive Nutzer bereitgestellt werden müssen (d. h. Inhalte, die keine HTML- oder JavaScript-Inhalte sind, z. B. Bilder und Downloads), kann dies jetzt ohne eine isolierte Sandboxdomain sicher erfolgen. Es gibt zwei wichtige Schritte:

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

X-Content-Type-Options: nosniff

Verhindert das Auslesen von Inhalten

Content-Disposition: attachment; filename="download"

Lösen einen Download statt eines Renderings aus

Content-Security-Policy: sandbox

Die Inhalte werden in einer Sandbox gehostet, als würden sie auf einer separaten Domain bereitgestellt.

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

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

Cross-Origin-Resource-Policy: same-site

Verhindert, dass die Seite websiteübergreifend eingeschlossen wird

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

Gestaffelte Sicherheitsebenen

Die oben genannte Lösung bietet zwar in der Regel einen ausreichenden Schutz vor XSS, es gibt aber eine Reihe weiterer Maßnahmen zur Härtung, die Sie anwenden können, um zusätzliche Sicherheitsebenen zu schaffen:

  • Legen Sie einen X-Content-Security-Policy: sandbox-Header für die Kompatibilität mit IE11 fest.
  • Lege einen Content-Security-Policy: frame-ancestors 'none'-Header fest, um das Einbetten des Endpunkts zu verhindern.
  • So legen Sie Nutzerinhalte in einer Sandbox auf einer isolierten Subdomain ab:
    • Bereitstellung 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 ursprungsübergreifende Isolierung zu aktivieren.

Ansatz 2: Inhalte für aktive Nutzer bereitstellen

Aktive Inhalte wie HTML- oder SVG-Bilder können auch ohne die Schwächen des klassischen Ansatzes mit Sandbox-Domains sicher bereitgestellt werden.
Die einfachste Option besteht darin, den Content-Security-Policy: sandbox-Header zu verwenden, um den Browser anzuweisen, die Antwort zu isolieren. Derzeit implementieren nicht alle Webbrowser die Prozessisolierung für Sandbox-Dokumente. Durch kontinuierliche Verbesserungen der Browserprozessmodelle wird die Trennung von Sandbox-Inhalten von eingebetteten Anwendungen jedoch wahrscheinlich verbessert. Wenn SpectreJS- und Renderer-Kompromittierungsangriffe nicht in Ihrem Bedrohungsmodell enthalten sind, ist die Verwendung einer CSP-Sandbox wahrscheinlich eine ausreichende Lösung.
Wir haben eine Lösung entwickelt, mit der nicht vertrauenswürdige aktive Inhalte vollständig isoliert werden können, indem das Konzept von Sandbox-Domains modernisiert wird. Der Grundgedanke 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 dafür sorgen, dass foo.exampleusercontent.com und bar.exampleusercontent.com websiteübergreifend und somit vollständig voneinander getrennt 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-Ereignis-Handler wartet und alle empfangenen Inhalte rendert.
  • Dazu erstellt das Produkt entweder einen Iframe oder ein Pop-up für $RANDOM_VALUE.exampleusercontent.com/shim und sendet die nicht vertrauenswürdigen Inhalte über postMessage zum Rendern an den Shim.
  • Die gerenderten Inhalte werden in einen Blob umgewandelt und in einem Sandbox-iFrame gerendert.

Im Vergleich zum klassischen Ansatz mit einer Sandbox-Domain werden so alle Inhalte vollständig auf einer einzelnen Website isoliert. Da die Hauptanwendung das Abrufen der zu rendernden Daten übernimmt, müssen keine Funktions-URLs mehr verwendet werden.

Fazit

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