Leitfaden zur Bedrohungsminderung für ASP.NET Core Blazor statisches serverseitiges Rendering

In diesem Artikel werden die Sicherheitsaspekte erläutert, die Entwickler beim Entwickeln von Blazor-Web Apps mit statischem serverseitigem Rendering berücksichtigen sollten.

Blazor kombiniert drei verschiedene Modelle in einem Modell zum Schreiben interaktiver Web-Apps. Herkömmliches serverseitiges Rendering, das auf HTTP basiert, ist ein Anforderungs-/Antwortmodell. Das interaktive serverseitige Rendering ist ein Renderingmodell, das auf SignalR basiert. Und schließlich das Renderingmodell des clientseitigen Renderings, das auf WebAssembly basiert.

Alle allgemeinen Sicherheitsaspekte, die für die interaktiven Renderingmodi definiert sind, gelten für Blazor-Web Apps, wenn die interaktiven Komponenten in einem der unterstützten Rendermodi gerendert werden. In den folgenden Abschnitten werden die Sicherheitsüberlegungen erläutert, die speziell auf das nicht interaktive serverseitige Rendering in Blazor-Web Apps und die spezifischen Aspekte zutreffen, die beim Interagieren mit Rendermodi gelten.

Allgemeine Überlegungen zum serverseitigen Rendering

Das serverseitige Renderingmodell (SSR) basiert auf dem herkömmlichen Anforderungs-/Antwortmodell von HTTP. Daher gibt es gemeinsame Bedenken zwischen SSR und Anforderungs-/Antwort-HTTP. Allgemeine Sicherheitsüberlegungen und spezifische Bedrohungen müssen erfolgreich abgemildert werden. Das Framework bietet integrierte Mechanismen zum Verwalten einiger dieser Bedrohungen, andere Bedrohungen sind jedoch spezifisch für App-Code und müssen von der App selbst behandelt werden. Diese Bedrohungen können wie folgt kategorisiert werden:

  • Authentifizierung und Autorisierung: Die App muss sicherstellen, dass der Benutzer authentifiziert und autorisiert ist, auf die App und die verfügbaren Ressourcen zuzugreifen. Das Framework bietet integrierte Mechanismen für die Authentifizierung und Autorisierung, die App muss jedoch sicherstellen, dass die Mechanismen ordnungsgemäß konfiguriert und verwendet werden. Die integrierten Mechanismen für die Authentifizierung und Autorisierung werden im Server-Sicherheitsknoten der Blazor-Dokumentation und in Security und Identity-Knoten der ASP.NET Core-Dokumentation behandelt, sodass sie hier nicht enthalten sind.

  • Eingabeüberprüfung und Bereinigung: Alle Eingaben, die von einem Client empfangen werden, müssen überprüft und vor der Verwendung bereinigt werden. Andernfalls kann die App Angriffen ausgesetzt sein, z. B. SQL-Einfügung, websiteübergreifender Skripterstellung, websiteübergreifender Anforderungsfälschung, offener Umleitung und anderer Arten von Angriffen. Die Eingabe kann von überall aus der Anforderung stammen.

  • Sitzungsverwaltung: Die ordnungsgemäße Verwaltung von Benutzersitzungen ist wichtig, um sicherzustellen, dass die App nicht Angriffen ausgesetzt ist, z. B. Sitzungsbehebung, Session Hijacking und anderen Angriffe. In der Sitzung gespeicherte Informationen müssen ordnungsgemäß geschützt und verschlüsselt sein und der Code der App muss verhindern, dass ein böswilliger Benutzer Sitzungen erraten oder manipulieren kann.

  • Fehlerbehandlung und Protokollierung: Die App muss sicherstellen, dass Fehler ordnungsgemäß verarbeitet und protokolliert werden. Andernfalls kann die App Angriffen ausgesetzt sein, z. B. der Offenlegung von Informationen. Dies kann passieren, wenn die App vertrauliche Informationen in der Antwort zurückgibt oder wenn die App detaillierte Fehlermeldungen mit Daten zurückgibt, die zum Angriff auf die App verwendet werden können.

  • Datenschutz: Vertrauliche Daten müssen ordnungsgemäß geschützt sein, was auch für die App-Logik gilt, wenn sie auf WebAssembly ausgeführt wird, da sie problemlos rückwärts abgeleitet werden kann.

  • Denial of Service: Die App muss sicherstellen, dass sie nicht für Angriffe verfügbar gemacht wird, z. B. Denial of Service. Dies geschieht beispielsweise, wenn die App nicht ordnungsgemäß vor Brute-Force-Angriffen geschützt ist oder eine Aktion dazu führen kann, dass die App zu viele Ressourcen verbraucht.

Eingabeüberprüfung und Bereinigung

Alle vom Client eingehenden Eingaben müssen als nicht vertrauenswürdig betrachtet werden, es sei denn, ihre Informationen wurden auf dem Server generiert und geschützt, z. B. ein CSRF-Token, ein Authentifizierungs-cookie, ein Sitzungsbezeichner oder eine andere Nutzlast, die mit authentifizierter Verschlüsselung geschützt ist.

Eingaben stehen in der Regel über einen Bindungsprozess für die App zur Verfügung, z. B. über das [SupplyParameterFromQuery]-Attribut oder das [SupplyParameterFromForm]-Attribut. Vor der Verarbeitung dieser Eingabe muss die App sicherstellen, dass die Daten gültig sind. Die App muss beispielsweise bestätigen, dass beim Zuordnen der Formulardaten zu einer Komponenteneigenschaft keine Bindungsfehler aufgetreten sind. Andernfalls verarbeitet die App möglicherweise ungültige Daten.

Wenn die Eingabe zum Ausführen einer Umleitung verwendet wird, muss die App sicherstellen, dass die Eingabe gültig ist und nicht auf eine Domäne verweist, die als ungültig eingestuft wurde, oder auf einen ungültigen Unterpfad innerhalb des App-Basispfads. Andernfalls kann die App für Umleitungsangriffe gefährdet sein, bei denen ein Angreifer einen Link erstellen kann, der den Benutzer zu einer schädlichen Website umleitet.

Wenn die Eingabe zum Ausführen einer Datenbankabfrage verwendet wird, muss die App bestätigen, dass die Eingabe gültig ist und dass sie die App nicht SQL-Einfügungsangriffen aussetzt. Andernfalls kann ein Angreifer möglicherweise eine bösartige Abfrage erstellen, mit der Informationen aus der Datenbank extrahiert oder die Datenbank geändert werden kann.

Daten, die möglicherweise aus einer Benutzereingabe stammen, müssen ebenfalls bereinigt werden, bevor sie in eine Antwort eingebunden werden können. Die Eingabe kann z. B. HTML oder JavaScript enthalten, die zum Ausführen websiteübergreifender Skriptingangriffe verwendet werden können, die zum Extrahieren von Informationen vom Benutzer oder zum Ausführen von Aktionen im Auftrag des Benutzers verwendet werden können.

Das Framework bietet die folgenden Mechanismen zur Unterstützung der Eingabeüberprüfung und -bereinigung:

  • Alle gebundenen Formulardaten werden auf grundlegende Korrektheit überprüft. Wenn eine Eingabe nicht analysiert werden kann, meldet der Bindungsprozess einen Fehler, den die App ermitteln kann, bevor Sie eine Aktion mit den Daten ausführt. Die integrierte EditForm-Komponente berücksichtigt dies vor dem Aufrufen des OnValidSubmit-Formularrückrufs. Blazor verhindert, dass der Rückruf ausgeführt wird, wenn mindestens ein Bindungsfehler aufgetreten ist.
  • Das Framework verwendet ein Antifälschungs-Token, um vor websiteübergreifenden Anforderungsfälschungsangriffen zu schützen. Weitere Informationen finden Sie unter ASP.NET Core Blazor-Authentifizierung und -Autorisierung und ASP.NET Core Blazor-Formularübersicht.

Alle Eingaben und Berechtigungen müssen zum Zeitpunkt der Ausführung einer bestimmten Aktion auf dem Server überprüft werden, um sicherzustellen, dass die Daten zu diesem Zeitpunkt gültig und korrekt sind und dass der Benutzer die Aktion ausführen darf. Dieser Ansatz entspricht den Sicherheitsanweisungen für das interaktive serverseitige Rendering.

Sitzungsverwaltung

Die Sitzungsverwaltung wird vom Framework behandelt. Das Framework verwendet eine Sitzung cookie, um die Benutzersitzung zu identifizieren. Die Sitzung cookie wird mithilfe der ASP.NET Kerndatenschutz-APIs geschützt. Auf die Sitzung cookie kann nicht mit JavaScript-Code, der im Browser ausgeführt wird, zugegriffen werden, und sie kann nicht einfach von einem Benutzer erraten oder manipuliert werden.

In Bezug auf andere Sitzungsdaten, z. B. Daten, die in Diensten gespeichert sind, sollten die Sitzungsdaten in bereichsbezogenen Diensten gespeichert werden, da bereichsbezogene Dienste pro benutzerbezogene Sitzung eindeutig sind, im Gegensatz zu Singleton-Diensten, die in allen Benutzersitzungen in einer bestimmten Prozessinstanz gemeinsam genutzt werden.

Bei SSR gibt es in den meisten Fällen keinen großen Unterschied zwischen bereichsbezogenen und vorübergehenden Diensten, da die Lebensdauer des Dienstes auf eine einzelne Anforderung beschränkt ist. Es gibt einen Unterschied in zwei Szenarien:

  • Wenn der Dienst an mehreren Orten oder zu unterschiedlichen Zeiten während der Anforderung eingefügt wird.
  • Wenn der Dienst in einem interaktiven Serverkontext verwendet werden kann, bei dem er mehrere Renderings überdauert, ist es grundlegend, dass der Dienst auf die Benutzersitzung festgelegt ist.

Fehlerbehandlung und Protokollierung

Das Framework bietet integrierte Protokollierung für die App auf Frameworkebene. Das Framework protokolliert wichtige Ereignisse, z. B. wenn das Antifälschungs-Token für ein Formular nicht überprüft werden kann, wenn eine Stammkomponente zu rendern beginnt und wenn eine Aktion versandt wird. Die App ist für die Protokollierung anderer Ereignisse verantwortlich, die möglicherweise wichtig für die Aufzeichnung sind.

Das Framework bietet eine integrierte Fehlerbehandlung für die App auf Frameworkebene. Das Framework behandelt Fehler, die während des Renderns einer Komponente auftreten, und verwendet entweder den Fehlerbegrenzungsmechanismus, um eine anzeigefreundliche Fehlermeldung anzuzeigen, oder ermöglicht es dem Fehler, die Middleware für die Ausnahmebehandlung aufzublasen, die so konfiguriert ist, dass die Fehlerseite gerendert wird.

Fehler, die während des Streamingrenderings auftreten, nachdem die Antwort an den Client gesendet wurde, werden in der endgültigen Antwort als generische Fehlermeldung angezeigt. Details zur Ursache des Fehlers sind nur während der Entwicklung enthalten.

Datenschutz

Das Framework bietet Mechanismen zum Schutz vertraulicher Informationen für eine bestimmte Benutzersitzung und stellt sicher, dass die integrierten Komponenten diese Mechanismen verwenden, um vertrauliche Informationen zu schützen, z. B. den Schutz der Benutzeridentität bei Verwendung der cookie-Authentifizierung. Außerhalb von Szenarien, die vom Framework behandelt werden, ist der Entwicklercode für den Schutz anderer appspezifischer Informationen verantwortlich. Am häufigsten erfolgt dies über die ASP.NET Core-Datenschutz-APIs oder eine andere Art von Verschlüsselung. Im Allgemeinen ist die App für Folgendes verantwortlich:

  • Sicherstellen, dass ein Benutzer die privaten Informationen eines anderen Benutzers nicht prüfen oder ändern kann.
  • Stellen Sie sicher, dass ein Benutzer keine Benutzerdaten eines anderen Benutzers ändern kann, wie z. B. einen internen Bezeichner.

Im Hinblick auf den Datenschutz müssen Sie klar verstehen, wo der Code ausgeführt wird. Beim statischen serverseitigen Rendering (statisches SSR) und beim interaktiven serverseitigen Rendering (interaktives SSR) wird der Code auf dem Server gespeichert und erreicht den Client nie. Für den Interaktiven WebAssembly-Rendermodus erreicht der App-Code immer den Client. Dies bedeutet, dass alle im App-Code gespeicherten vertraulichen Informationen für alle Benutzer mit Zugriff auf die App verfügbar sind. Verschleierung und andere ähnliche Techniken zum „Schützen“ des Codes sind nicht effektiv. Sobald der Code den Client erreicht hat, kann er rückwärts abgeleitet werden, um die vertraulichen Informationen zu extrahieren.

Denial of Service

Auf Serverebene bietet das Framework Beschränkungen für Anforderungs-/Antwortparameter, z. B. die maximale Größe der Anforderung und die Headergröße. Im Hinblick auf den App-Code definiert das Formularzuordnungssystem von Blazor Grenzwerte, die denen des Modellbindungssystems von MVC ähneln:

  • Grenzwert für die maximale Anzahl von Fehlern.
  • Grenzwert für die maximale Rekursionstiefe für den Binder.
  • Grenzwert für die maximale Anzahl von Elementen, die in einer Auflistung gebunden sind.

Darüber hinaus sind Grenzwerte für das Formular definiert, z. B. die maximale Größe und Wertgröße des Formularschlüssels und die maximale Anzahl von Einträgen.

Im Allgemeinen muss die App ausgewertet werden, wenn die Wahrscheinlichkeit besteht, dass eine Anforderung eine asymmetrische Menge an Arbeit durch den Server auslöst. Beispiele hierfür sind, wenn der Benutzer eine von N parametrisierte Anforderung sendet und der Server einen Vorgang N-mal so aufwendig ausführt, wobei N ein Parameter ist, den ein Benutzer steuert, und der unbegrenzt wachsen kann. Normalerweise muss die App entweder einen Grenzwert für den maximalen N festlegen, den sie verarbeiten möchten, oder sicherstellen, dass jeder Vorgang entweder kleiner, gleich oder aufwendiger ist, als die Anforderung durch einen konstanten Faktor.

Dieser Aspekt hat mehr zu tun mit dem Unterschied zwischen der Arbeit, die der Client ausführt, und der Arbeit, die der Server ausführt, als mit einem bestimmten Vergleich von 1→N. Beispielsweise kann ein Client eine Arbeitsaufgabe (Einfügen von Elementen in eine Liste) übermitteln, die N-Zeit für die Ausführung benötigt, der Server benötigt jedoch N^2^-mal so lange, um sie zu verarbeiten (da er möglicherweise etwas sehr naiv ausführt). Der Unterschied zwischen N und N^2^ ist entscheidend.

Daher gibt es ein Limit für die Arbeit, die der Server ausführen muss, das für die App spezifisch ist. Dieser Aspekt gilt für serverseitige Workloads, da sich die Ressourcen auf dem Server befinden, aber in den meisten Fällen nicht unbedingt für WebAssembly-Workloads auf dem Client verwendet werden.

Der andere wichtige Aspekt ist, dass dies nicht nur auf die CPU-Zeit zutrifft. Es gilt auch für alle Ressourcen, z. B. Arbeitsspeicher, Netzwerk und Speicherplatz auf dem Datenträger.

Bei WebAssembly-Workloads gibt es in der Regel wenig Bedenken hinsichtlich der vom Client ausgeführten Arbeit, da der Client normalerweise auf die Ressourcen beschränkt ist, die auf dem Client verfügbar sind. Es gibt jedoch einige Szenarien, in denen der Client beeinträchtigt werden kann, wenn beispielsweise eine App Daten von anderen Benutzern anzeigt und ein Benutzer Daten zum System hinzufügen kann, welche die Clients zwingen, die Daten anzuzeigen, um eine Menge Arbeit auszuführen, die nicht proportional zur Menge der vom Benutzer hinzugefügten Daten ist.

  • Stellen Sie sicher, dass der Benutzer authentifiziert und autorisiert ist, auf die App und die verfügbaren Ressourcen zuzugreifen.
  • Überprüfen und bereinigen Sie alle Eingaben, die von einem Client stammen, bevor Sie sie verwenden.
  • Verwalten Sie Benutzersitzungen ordnungsgemäß, um sicherzustellen, dass der Zustand nicht versehentlich für alle Benutzer freigegeben wird.
  • Behandeln und protokollieren Sie Fehler ordnungsgemäß, um die Offenlegung vertraulicher Informationen zu vermeiden.
  • Protokollieren Sie wichtige Ereignisse in der App, um potenzielle Probleme und Überwachungsaktionen zu identifizieren, die von Benutzern ausgeführt werden.
  • Schützen Sie vertrauliche Informationen mithilfe der ASP.NET Core-Datenschutz-APIs oder einer der verfügbaren Komponenten (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage, PersistentComponentState).
  • Stellen Sie sicher, dass die App die Ressourcen versteht, die von einer bestimmten Anforderung genutzt werden können, und die vorhandenen Einschränkungen, um Denial-of-Service-Angriffe zu vermeiden.