Læringsmål
- Forklare XSS og Blazors default encoding vs
MarkupString. - Beskytte API-nøgler og Bearer tokens i SPA.
- Forstå CORS fra browserens perspektiv (WASM vs Server).
- Anvende WASM/hosting-tips til mindre payload og færre re-renders.
Hvornår tænke sikkerhed først? Når I viser bruger-/API-tekst, gemmer tokens eller nøgler i browseren, eller deployer WASM hvor alt kan downloades og inspiceres.
Tjek dig selv før du går videre
- Du encoder brugerdata før visning (XSS-lab).
- Du gemmer ikke secrets i git eller localStorage.
- Du har besvaret quiz om CORS/tokens.
XSS og brugerinput
Cross-Site Scripting: angriber får script kørt i offerets browser. Blazor encoder tekst i @variable som standard. Farligt: rå HTML fra bruger eller API uden sanitizing.
Encode vs raw
Indtast tekst med <script> — se forskel på sikker encoding og usikker raw HTML.
@* Sikkert *@ <p>@userComment</p> @* Farligt hvis userComment kommer fra bruger *@ <p>@((MarkupString)userComment)</p>
Hvornår CSP (idé)? I produktion kan Content-Security-Policy begrænse inline script — relevant hvis I tilføjer tredjeparts widgets. I skoleprojekter: prioriter encode + ingen MarkupString på user input; CSP er et hosting/nginx-emne ved Dokploy.
Tokens og API-nøgler
- Commit aldrig nøgler/tokens til git — brug env og user secrets.
- Send
X-Api-Keyi header, ikke i URL (logs, referrer). - Bearer tokens: kort levetid, sessionStorage, refresh med rotation.
- Alt i WASM kan inspiceres — skjul ikke «hemmeligheder» i klientkode.
Trin ved nøgle-læk i git: roter nøgle på kataloget, fjern fra historie hvis nødvendigt, flyt til sessionStorage-flow, dokumentér i testplan at gammel nøgle giver 401.
CORS
Browsere håndhæver CORS på cross-origin fetch. Blazor WASM kalder API fra browser → CORS skal tillade jeres origin. Blazor Server kalder ofte HttpClient fra server-processen → CORS gælder ikke samme vej, men browseren kalder stadig SignalR til jeres app-origin.
// På API ( ikke i Blazor ) — eksempel princip
// policy.WithOrigins("https://min-app.mercantec.tech").AllowAnyHeader();
Hvornår proxy via egen api? Når I ikke kan ændre OpgaverAPI CORS, men skal kalde fra WASM på nyt domæne — browser → jeres backend → OpgaverAPI med server-side nøgle (pas på: nøgle må stadig ikke lække til klient).
Performance
- Reducer re-renders: stabile parametre,
ShouldRender, undgå unødige state-ændringer i loop. - Virtualisér lange lister (
Virtualizekomponent) til store Pokémon-datasæt. - WASM: trimming, compression (Brotli), lazy load tunge routes.
- Paginér API (
?limit=) — hent ikke 10.000 records til UI. - Cache read-only data kort i scoped service med etag/expiration.
WASM trim: I .csproj kan <PublishTrimmed>true</PublishTrimmed> (med forsigtighed — test grundigt) reducere download. Kombiner med Brotli på static host. Pokémon-liste med 500 items: brug Virtualize + limit= — ikke render 500 DOM-noder på mobil.
<PropertyGroup> <PublishTrimmed>true</PublishTrimmed> <InvariantGlobalization>true</InvariantGlobalization> </PropertyGroup>
Faldgrube: At gemme elev-API-nøgle i appsettings.json i Blazor WASM-projekt — filen downloades til klienten. Nøgler der kun må kende én bruger hører i sessionStorage efter login, eller proxyes via jeres backend.
Quiz 1
Hvordan viser I sikkert brugerkommentar i Razor?
Quiz 2
Hvorfor paginere OpgaverAPI-kald i UI?
Hvorfor det betyder noget: API-nøgle i localStorage + raw HTML fra LoL-navne = klassisk XSS + token-tyveri.
Sådan fejler det i praksis: @((MarkupString)userInput) i fejlmeddelelse — lab viser hvorfor encode altid.
Mini-opgave
XSS-lab med <script> i input — sammenlign encode vs raw.
Quiz 3
Vis champion-navn fra API i Blazor?
Læs hos Microsoft
Prøv med API
- Opret nøgle under kataloget — verificér den ikke ligger i git history.
- Sammenlign payload-størrelse:
limit=3vslimit=500på Pokémon.
Baseret på MAGS Blazor-wiki og Microsoft Learn — Blazor.