Sicherheit und Server ActionseQuantic.UI erleichtert die Kommunikation zwischen Client und Server über Server Actions und stellt dabei sicher, dass diese Brücke von vornherein sicher ist.
Eine Server Action ist eine C#-Methode, die in einer Komponente definiert ist und direkt aus dem Browser aufgerufen werden kann. Der Compiler erzeugt die Aufrufbrücke (Fetch API) automatisch, und die Middleware des Servers löst die Ausführung auf.
[Authorize(Roles = "Admin")]
public async Task<bool> DeleteUser(Guid userId) {
// Logik, die nur auf dem Server läuft
🔒 Eine Seite, die Autorisierung verlangt
Seit 0.2.0-preview.61
[Page("/backoffice/queue")]
[Authorize(Policy = "Backoffice")]
public sealed class VerificationQueuePage : StatefulComponent, IServerPrefetch { … }
Dieselben [Authorize] und [AllowAnonymous], die eine Server Action nimmt, bewachen eine Seite. Ihre Route trägt sie als Endpoint-Metadaten, wie RequireAuthorization es täte, also entscheidet die Autorisierung von ASP.NET Core mit den Schemata und Richtlinien, die die Anwendung konfiguriert hat (AddAuthentication, AddAuthorization):
•
ein anonymer vollständiger Laden wird vom Standardschema herausgefordert, zum Beispiel durch die OpenID-Connect-Umleitung zur Anmeldung;
•
eine angemeldete Besucherin ohne die Richtlinie bekommt 403;
•
eine Client-Navigation in die Seite bekommt ein 401 oder ein 403 statt der Seite, und der Router lädt die Route dann vollständig, sodass die Herausforderung oder das 403 geschieht, wie es bei jedem Besuch geschähe;
•
eine abgelehnte Anfrage erreicht die Seite nie: Ihr IServerPrefetch läuft nicht, und keines ihrer Felder wird in das HTML geschrieben.
[Authorize] ohne Richtlinie verlangt nur eine angemeldete Besucherin. Unter einer anwendungsweiten FallbackPolicy wird eine mit [AllowAnonymous] markierte Seite (die Anmeldeseite) weiter ausgeliefert, und ebenso die Runtime und die Seitenmodule, die sie braucht. Ein [Authorize] auf Klassenebene bewachte früher nur die Server Actions der Seite; es bewacht nun auch die Seite.
Den 404- und 500-Seiten, die eine Anwendung registriert, wird dieselbe Frage gestellt, bevor sie anstelle einer Route gezeichnet werden, so wie ihre eigenen Routen sie stellen: Eine Seite, die keine Anforderung nennt, steht unter der FallbackPolicy, die Anfrage ist die Ressource der Richtlinie, und eine Seite, die die Besucherin nicht sehen darf, wird nicht gezeichnet, und ihr IServerPrefetch läuft auch nicht.
eQuantic.UI unterstützt die Attribute [Authorize] und [AllowAnonymous].
•
Die ServerActionsMiddleware prüft, ob der aktuelle Nutzer die nötigen Rechte hat, bevor die Methode aufgerufen wird.
•
Scheitert die Autorisierung, gibt der Server einen 403 Forbidden- oder 401 Unauthorized-Fehler zurück und blockiert die Ausführung der Geschäftslogik.
Um Injektionsangriffe und übermäßigen Ressourcenverbrauch zu verhindern:
•
Größenbegrenzung: Die Middleware setzt strikte Grenzen für die Größe des Anfragekörpers.
•
Typ-Whitelist: Die Deserialisierung der Argumente ist auf bekannte und sichere Typen beschränkt, was Angriffe durch unsichere Deserialisierung verhindert.
3. Registrierung der Aktionen
Nur Methoden, die ausdrücklich mit [ServerAction] markiert sind, können aufgerufen werden. Es ist nicht möglich, eine beliebige öffentliche Methode über die API aufzurufen, womit die Angriffsfläche beherrscht bleibt.
Seit 0.2.0-preview.61
Eine Server Action lehnt eine Anfrage ab, die die Seite einer anderen Website sendet, bevor etwas davon gelesen wird. Der Browser sagt, woher eine Anfrage kam, und der Endpoint antwortet 403 Forbidden, wenn:
•
die Origin weder der eigene Host der Anwendung noch eine von der Anwendung erlaubte Origin ist, das opake Origin: null eingeschlossen;
•
es keine Origin gibt und Sec-Fetch-Site cross-site oder same-site sagt.
Eine Anfrage ohne beide Header ist nicht die eines Browsers und läuft. Der eigene Host der Anwendung ist der Host der Anfrage: Hinter einem Proxy, der ihn umschreibt, stellt app.UseForwardedHeaders() ihn aus den Proxies wieder her, denen die Anwendung vertraut, und ein rohes X-Forwarded-Host wird nie gelesen. Host und Port werden verglichen, nicht das Schema, und ein Host ohne Port steht für den Standardport der Origin, eine Anwendung hinter einem Proxy, der TLS beendet, braucht also keine Einstellung.
Eine Seite, die von einer anderen Domain als ihre Aktionen ausgeliefert wird, führt diese Origin auf, in der appsettings.json:
"AllowedOrigins": [ "https://admin.example.com" ]
oder in der Program.cs:
builder.Services.AddUI(options => options.AllowServerActionOrigins("https://admin.example.com"));
Jede Origin ist scheme://host[:port], ohne Pfad und ohne Query. Eine, die das nicht ist, hält die Anwendung beim Start an und nennt den Wert.
📡 Kommunikationsprotokoll
Die Kommunikation läuft per HTTP POST an den reservierten Endpoint /api/_equantic/actions.
•
Payload: enthält die eindeutige Id der Action und die Liste der serialisierten Argumente.
•
Antwort: gibt das Ergebnisobjekt oder einen strukturierten Fehler zurück.