Security, infrastructuur, secrets en omgevingen
20.1 Doel en scope
Dit hoofdstuk beschrijft de technische securitybaseline voor OefenHub. Het hoofdstuk legt vast hoe security wordt toegepast in hosting, middleware, configuratie, secretsbeheer, omgevingen, browseropslag, databasebereik, dependencybeheer en operationele infrastructuur.
Security wordt in OefenHub niet ondergebracht in één apart OefenHub.Security project. De reden daarvoor is dat de meeste securitymaatregelen technisch thuishoren in bestaande lagen:
| Onderwerp | Primaire plaats |
|---|---|
| Authenticatie-integratie en accountkoppeling | OefenHub.Identity |
| Rolcontext, policies en server-side autorisatiecontrole | OefenHub.Authorization |
| Middleware, headers, cookies, rate limiting en request pipeline | OefenHub.Web |
| Hosting-, netwerk-, configuratie- en providerintegratie | OefenHub.Infrastructure en hostingomgeving |
| Jobtoegang, jobstatussen, TickerQ-dashboard en retrybeheer | OefenHub.Scheduling |
| Domeinspecifieke toegangscontrole en audit/history | Eigenaar-module van het betreffende domein |
| Technische logging, securitylogging en foutafhandeling | Technisch Ontwerp: logging, audit, securitylogging en technische foutafhandeling |
| Privacy, retentie en anonimisering | Technisch Ontwerp: privacy, retentie, anonimisering en gegevensbescherming |
Het ontbreken van een apart securityproject betekent dus niet dat security impliciet blijft. Dit hoofdstuk maakt expliciet welke securityverantwoordelijkheid waar wordt belegd en welke technische randvoorwaarden voor alle modules gelden.
20.2 Ontwerpprincipes
Voor de technische security-inrichting gelden de volgende basisprincipes.
| Principe | Uitwerking |
|---|---|
| Server-side vertrouwen | Autorisatie, rolcontext, objecttoegang en datatoegang worden server-side bepaald. Clientstate, routes, querystrings, zichtbare knoppen of browseropslag zijn nooit autoriserend. |
| Eén applicatie, meerdere grenzen | OefenHub is één deploybare applicatie, maar modulegrenzen, DbContexts, schemas en publieke contracten beperken ongewenste koppeling. |
| Geen securitydoorbraak via gemak | UI-compositie, readmodels, caching, SignalR, PDF-export en jobs mogen de server-side autorisatiegrenzen niet verruimen. |
| Geen credentials in OefenHub | Wachtwoorden, credentialvalidatie en identity-providerinterne gegevens blijven buiten OefenHub. OefenHub verwerkt alleen de uitkomst van externe authenticatie en de eigen applicatiecontext. |
| Secrets buiten code | Secrets, connectionstrings, client secrets, certificaatwachtwoorden en tokens staan niet in broncode of versiebeheer. |
| Securityconfiguratie als code | Headers, middleware, rate limits, cookiebeleid en environment-afhankelijke opties worden expliciet geconfigureerd en gevalideerd. |
| Minimaal lekken | Foutmeldingen aan gebruikers zijn generiek. Technische details komen alleen in beveiligde logs met correlation-id. |
| Herleidbaarheid | Securityrelevante gebeurtenissen krijgen correlation-id’s en voldoende context voor analyse zonder credentials, tokens of gevoelige payloads te loggen. |
20.3 Omgevingen
OefenHub gebruikt gescheiden omgevingen met eigen configuratie en eigen secrets. Omgevingsverschillen mogen niet worden opgelost met handmatige codewijzigingen.
| Omgeving | Doel | Security-uitgangspunt |
|---|---|---|
| Local | Lokale ontwikkeling | Lokale secrets via veilige developermechanismen, geen productiegegevens, debugmogelijkheden toegestaan. |
| Development | Gedeelde ontwikkelomgeving | Geen productiegegevens, beperkte externe toegang, logging mag uitgebreider zijn maar zonder secrets of tokens. |
| Test | Technische en functionele verificatie | Realistische configuratie, testdata, geen productiecredentials, migrations en jobs testbaar. |
| Acceptance | Pre-productieacceptatie | Productie-achtige securityconfiguratie, beperkte toegang, representatieve maar gecontroleerde data. |
| Production | Productiegebruik | Strikte securityheaders, HTTPS, HSTS, minimale foutdetails, bewaakte job- en logomgeving. |
20.3.1 Environment-afhankelijke configuratie
Configuratie wordt per omgeving geladen via appsettings, environment variables, secret stores of hostingconfiguratie. De applicatie bindt configuratie naar strongly typed options/DTO’s en valideert verplichte waarden bij startup.
Voorbeelden van configuratiegroepen:
OefenHubOptions
IdentityProviderOptions
DatabaseOptions
SignalROptions
TickerQOptions
PdfExportOptions
SecurityHeaderOptions
RateLimitOptions
StorageOptions
LoggingOptions
Regels:
- Productie mag niet starten met ontbrekende kritieke configuratie.
- Productie mag niet starten met development-only defaults voor securitygevoelige waarden.
- Configuratiefouten worden technisch gelogd, maar secrets worden nooit in logs opgenomen.
- Voor lokale ontwikkeling mogen veilige developer defaults bestaan, maar alleen wanneer de omgeving expliciet
DevelopmentofLocalis.
20.3.2 Aspire voor development-pariteit
Aspire wordt in de technische baseline gebruikt als development-only ondersteuning voor lokale configuratie-, dependency- en secrets-pariteit. Het doel is dat lokale ontwikkeling, testachtige services en configuratiebinding voorspelbaar blijven zonder productieconfiguratie in broncode of lokale scripts te dupliceren.
Regels:
- Aspire is geen productie-afhankelijkheid in de V1.0-baseline, tenzij een later Technisch Ontwerp-besluit dat expliciet wijzigt.
- Aspire mag geen secrets in broncode, documentatievoorbeelden of versiebeheer introduceren.
- Developmentconfiguratie via Aspire moet dezelfde options- en startupvalidatiepaden gebruiken als andere omgevingen.
- Afwijkingen tussen Aspire-development en test/acceptatie/productie worden als configuratieverschil gedocumenteerd, niet als stille codevariant.
20.3.3 Validatie-uitkomst Aspire-developmentpariteit
De developmentpariteit voor Aspire is voldoende afgebakend voor de V1.0-baseline. Aspire wordt niet als open architectuurvraag behandeld, maar als concrete development-only inrichting met vaste guardrails.
| Onderdeel | Baselineafspraak | Validatie |
|---|---|---|
| Scope | Aspire wordt alleen gebruikt voor lokale ontwikkeling en eventueel technische smoke checks. | Niet-lokale deployment kan OefenHub.Web starten zonder Aspire AppHost. |
| Projectgrens | Een eventuele OefenHub.AppHost of vergelijkbare development host staat buiten domein-, applicatie- en datamodules. | Productieprojecten refereren niet naar de development host. |
| Afhankelijkheden | Aspire mag lokale infrastructuur modelleren zoals SQL Server, lokale identity provider, Seq en ondersteunende containers. | De gemodelleerde resources corresponderen met dezelfde functionele afhankelijkheden als test/acceptatie/productie. |
| Configuratiebinding | Development gebruikt dezelfde optionsclasses, configuratiesleutels en startupvalidatie als andere omgevingen. | Een configuratiefout faalt in development op dezelfde validatieklasse als buiten development. |
| Secrets | Aspire bevat geen echte secrets, tokens, productiewaarden of persoonsgegevens in broncode, manifesten of documentatievoorbeelden. | Secrets komen uit developer secrets, lokale environmentvariabelen of een lokale secret store. |
| Data | Lokale databases, volumes en testdata zijn developmentdata en geen bron van waarheid. | Productiedata, backups en exports worden niet via Aspire-development ingericht. |
| Observability | Aspire mag lokale observability en dashboardinformatie tonen voor ontwikkelaars. | Operationele loggingbaseline blijft Serilog + Seq; Aspire vervangt geen productiebeheer of monitoring. |
| Documentatie | Afwijkingen tussen lokale Aspire-inrichting en niet-lokale omgevingen worden expliciet als omgevingsverschil vastgelegd. | Er ontstaat geen stille codevariant of alternatieve businesslogica voor development. |
Daarmee is het open punt over Aspire-developmentpariteit opgelost. Latere wijzigingen aan deploymenttopologie, productie-Aspiregebruik of cloudspecifieke provisioning vereisen een nieuw Technisch Ontwerp-besluit.
20.4 Projectverdeling voor security-inrichting
Securityfunctionaliteit wordt verdeeld over bestaande projecten. Dit voorkomt een kunstmatig securityproject dat vooral pipeline- en configuratiecode zou verzamelen zonder eigen domeinverantwoordelijkheid.
| Project | Securityverantwoordelijkheid |
|---|---|
OefenHub.Web | Middlewarepipeline, HTTPS/HSTS, securityheaders, cookies, antiforgery waar relevant, rate limiting, foutpagina’s, Blazor/Razor boundaries, TickerQ-dashboard-afscherming. |
OefenHub.Identity | Koppeling tussen identity provider en intern account, provisioning, accountstatus, externe identity-id’s, geen credentialbeheer. |
OefenHub.Authorization | Policies, rolcontext, objecttoegang, server-side contextcontrole, access-denied afhandeling. |
OefenHub.Infrastructure | Technische providers, configuratiebinding, secret-/storage-integratie, externe services, infrastructuurhelpers. |
OefenHub.Scheduling | Jobtoegang, TickerQ-configuratie, interne jobinterface, joblogging, retrybeleid en failed-job beheer. |
| Domeinmodules | Domeineigen autorisatiecontroles, domeinhistorie, soft-link/snapshotgebruik, privacybewuste dataverwerking. |
Securitycode mag via een toekomstig Technisch Ontwerp-besluit worden afgesplitst als de omvang dat rechtvaardigt. Tot die tijd blijft de verdeling hierboven leidend.
20.5 Request pipeline en middlewarevolgorde
De exacte ASP.NET Core middlewarevolgorde moet in implementatie worden afgestemd op het gekozen Blazor-hostingmodel. Functioneel gelden de volgende regels.
| Stap | Doel |
|---|---|
| Exception handling | Centrale veilige foutafhandeling en correlation-id borging. |
| HTTPS redirection | HTTP-verkeer naar HTTPS sturen buiten lokale uitzonderingen. |
| HSTS | Browsers instrueren om HTTPS te gebruiken in productie. |
| Security headers | CSP, framebeleid, content-type bescherming, referrerbeleid en permissionsbeleid toepassen. |
| Static files | Alleen bedoelde statische bestanden leveren met passende caching en content-type bescherming. |
| Routing | Routes bepalen zonder autorisatiebeslissing op basis van clientstate. |
| Rate limiting | Misbruik en brute-forceachtige patronen beperken waar relevant. |
| Authentication | Identity-provideruitkomst verwerken. |
| Authorization | Policies en server-side autorisatie toepassen. |
| Antiforgery | Formulieren/endpoints beschermen waar het hostingmodel dit vereist. |
| Blazor/Razor endpoints | UI en interactieve componenten hosten. |
| SignalR hubs | Alleen geautoriseerde realtimeverbindingen toestaan. |
| TickerQ dashboard | Alleen intern en beheerd toegankelijk maken. |
Voorbeeldmatige pipeline-indeling:
app.UseExceptionHandler("/error");
app.UseHttpsRedirection();
app.UseHsts();
app.UseSecurityHeaders();
app.UseStaticFiles();
app.UseRouting();
app.UseRateLimiter();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.MapRazorComponents<App>();
app.MapHub<LiveMonitoringHub>("/hubs/live").RequireAuthorization();
app.MapTickerQDashboard("/internal/jobs").RequireAuthorization("InternalJobDashboard");
Deze code is illustratief. De definitieve implementatie volgt de gekozen .NET- en Blazorversie.
20.6 HTTPS, HSTS en transportbeveiliging
Productie en acceptatie gebruiken HTTPS. De applicatie mag in productie geen reguliere gebruikersflows via onbeveiligde HTTP aanbieden.
| Maatregel | Regel |
|---|---|
| HTTPS | Verplicht voor niet-lokale omgevingen. |
| HSTS | In productie actief, met passende max-age en alleen wanneer TLS correct is ingericht. |
| Secure cookies | Authenticatie- en sessiegerelateerde cookies zijn Secure. |
| Mixed content | Niet toegestaan in productiepagina’s. |
| WebSockets/SignalR | Alleen via beveiligde transporten in productie. |
| Interne dashboards | Alleen via intern netwerk, beheercontext of aanvullende afscherming. |
HSTS wordt niet zonder controle maximaal agressief ingesteld. Preload en includeSubDomains worden pas gebruikt als domeinbeheer, subdomeinen en certificaatbeheer daarop zijn voorbereid.
20.7 Securityheaders en CSP
Securityheaders worden centraal in OefenHub.Web geconfigureerd, bij voorkeur via extension methods zodat de pipeline leesbaar blijft.
CSP staat voor Content Security Policy. Dit is een browsermechanisme waarmee OefenHub beperkt van welke bronnen scripts, styles, afbeeldingen, fonts, connecties en frames geladen mogen worden. CSP moet zorgvuldig worden afgestemd op Blazor, SignalR, fonts, eventuele iconen en PDF/downloadgedrag.
| Header / beleid | Doel | Baseline |
|---|---|---|
| Content-Security-Policy | Beperkt toegestane script-, style-, image-, connect- en framebronnen. | Alleen noodzakelijke bronnen toestaan; SignalR/WebSocket expliciet meenemen. |
| Strict-Transport-Security | Dwingt HTTPS-gebruik af bij browsers. | Productie, na TLS-validatie. |
| X-Content-Type-Options | Voorkomt MIME-sniffing. | nosniff. |
| Referrer-Policy | Beperkt referrerlekken. | Strikt beleid, bijvoorbeeld strict-origin-when-cross-origin of strenger. |
| Permissions-Policy | Beperkt browserfeatures zoals camera, microfoon, geolocation. | Alleen toestaan wat OefenHub gebruikt; standaard uit. |
| Framebeleid | Beperkt framing/clickjacking. | Via CSP frame-ancestors; eventueel aanvullende legacy-header. |
| Cache-Control | Voorkomt caching van gevoelige pagina’s waar nodig. | Gevoelige responses niet publiek cachebaar. |
20.7.1 CSP-baseline
De V1.0-baseline gebruikt een expliciete Content-Security-Policy-header. De policy wordt centraal in OefenHub.Web gezet, niet per pagina. In development mag tijdelijk een Content-Security-Policy-Report-Only-variant worden gebruikt om Blazor, SignalR, MudBlazor, fonts en assets te valideren; productie gebruikt een afdwingende header.
Baseline voor productie:
default-src 'self';
base-uri 'self';
object-src 'none';
frame-ancestors 'none';
form-action 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob:;
font-src 'self' data:;
connect-src 'self' wss:;
worker-src 'self' blob:;
manifest-src 'self';
media-src 'none';
upgrade-insecure-requests
Regels:
- externe scripts, fonts, iconensets en CDN's zijn standaard niet toegestaan; benodigde assets worden bij voorkeur self-hosted;
script-srcgebruikt geen'unsafe-inline'; inline scripts vereisen een hash/nonce of herbouw naar externe/self-hosted scriptbestanden;style-src 'unsafe-inline'is alleen toegestaan als praktische baseline voor Blazor/MudBlazor/styling en moet beperkt blijven tot styles, niet scripts;connect-srcstaat in productie alleenselfen beveiligde WebSocketverbindingen toe; lokale development magws:en lokale hostnamen toevoegen;frame-ancestors 'none'voorkomt embedding/clickjacking, tenzij een later besluit expliciet embedding toestaat;- PDF-downloads, static files en images moeten binnen deze policy werken zonder extra externe bronnen;
- iedere verruiming van CSP wordt als security-impact behandeld en vastgelegd in configuratie, niet ad hoc in pagina's.
20.8 Cookies, sessies en browseropslag
Browseropslag mag geen autorisatiebron worden. Dit geldt voor cookies, local storage, session storage en overige client-side opslag.
| Opslag | Toegestaan | Niet toegestaan |
|---|---|---|
| Authenticatiecookie | Alleen via identity-/authmiddleware, secure en httpOnly waar mogelijk. | Eigen wachtwoorden, tokens of identity-providerinterne gegevens opslaan. |
| Technische toegankelijkheidscookie | Voor pre-login renderingvoorkeuren zoals contrast of dyslexielettertype. | Persoonsgegevens, rollen, autorisaties, account-id’s. |
| Once-per-browser notificatieonderdrukking | Alleen niet-persoonsgebonden notificatie-id/status. | Server-side seen-status of autorisatie vervangen. |
| Local/session storage | Alleen niet-gevoelige UI-state indien nodig. | Tokens, credentials, rolcontext, kind-id’s als autorisatiebewijs, oefenresultaten. |
Na login zijn server-side profiel- en gebruikersinstellingen leidend. Browserwaarden mogen hoogstens technische weergavevoorkeuren spiegelen en moeten veilig genegeerd kunnen worden wanneer zij ontbreken, corrupt of onbekend zijn.
20.9 Secretsbeheer
Secrets staan niet in broncode, documentatievoorbeelden, testdata of versiebeheer.
| Secrettype | Voorbeelden | Regels |
|---|---|---|
| Database | Connectionstring, wachtwoord | Via environment/secret store; niet loggen. |
| Identity provider | Client secret, realm/adminwaarden indien gebruikt | Alleen via veilige configuratie; niet tonen aan gebruiker. |
| Signing/encryption | Certificaatwachtwoorden, keys | Niet in appsettings in repository; rotatieplan nodig. |
| Storage/export | Bestandsopslagcredentials | Alleen omgeving-/secretgebonden. |
| SMTP/externe services indien toekomstig nodig | API keys, wachtwoorden | Alleen via secretmechanisme. |
Configuratiebinding gebeurt naar optionsclasses. Voorbeeld:
builder.Services
.AddOptions<IdentityProviderOptions>()
.Bind(builder.Configuration.GetSection("IdentityProvider"))
.ValidateDataAnnotations()
.ValidateOnStart();
Regels:
- Optionsclasses bevatten geen default productiecredentials.
- Validatie geeft aan welke configuratiesleutel ontbreekt, maar logt de geheime waarde niet.
- Lokale developersecrets zijn niet herbruikbaar in test, acceptatie of productie.
- Rotatie van secrets mag geen dataverlies veroorzaken en moet operationeel beschreven worden in beheerbeleid.
20.9.1 Secretbaseline voor Docker V1.0
Voor de eerste livegang gaat OefenHub uit van een eenvoudige Docker-hosted omgeving. Met het huidige inzicht is de veiligste V1.0-baseline een file-based secretinrichting buiten repository, containerimage en documentatievoorbeelden. Deze keuze is een pragmatische baseline op basis van de nu bekende deploymentrichting; zij garandeert nog niet de exacte operationele route wanneer hosting, Portainer-inrichting, Docker Compose, Docker Swarm of een latere cloudomgeving anders uitpakt.
| Omgeving | Secretbaseline V1.0 |
|---|---|
| Local/development | .NET user secrets, lokale secretbestanden of lokale environmentvariabelen buiten repository; geen productiesecrets. |
| Test/acceptatie in Docker | Docker Compose secrets of read-only gemounte secretbestanden buiten repository. |
| Productie Docker zonder Swarm | Docker Compose secrets of read-only gemounte secretbestanden buiten repository, beschikbaar als bestanden in de container. |
| Productie Docker Swarm/Portainer Swarm | Docker/Portainer Swarm secrets wanneer Swarm daadwerkelijk wordt gebruikt. |
| Kubernetes of cloud later | Kubernetes Secrets, Azure Key Vault, Vault of vergelijkbaar alleen na nieuw Technisch Ontwerp-besluit. |
Regels:
- secrets staan niet in broncode, Git, containerimages, Dockerfiles, appsettings in de repository, documentatievoorbeelden of seeddata;
- productie gebruikt geen gewone environment variables als primaire secretstore wanneer file-based secrets beschikbaar zijn;
- secrets worden bij voorkeur als bestanden beschikbaar gemaakt, bijvoorbeeld onder
/run/secrets, en gelezen via .NET-configuratie zoals key-per-file binding; - Docker Compose secrets of read-only mounted files gelden als de V1.0-standaard zolang er geen Swarm/Kubernetes/cloudsecretstore is gekozen;
- Portainer Secrets zijn alleen baseline wanneer de omgeving daadwerkelijk Docker Swarm of een andere Portainer-omgeving met secrets ondersteunt;
- secretbestanden krijgen minimale bestandsrechten en worden alleen gemount in containers die de betreffende secret nodig hebben;
- secretnamen mogen worden gelogd voor configuratievalidatie, maar secretwaarden nooit;
- rotatie en herstel worden operationeel beschreven voordat productie live gaat.
Onzekerheden:
- de exacte hostinginrichting en Portainer-modus kunnen de technische route beïnvloeden;
- wanneer Docker Compose secrets in de gekozen omgeving onvoldoende beheerbaar blijken, mag een read-only hostmount met strikte rechten als tijdelijke V1.0-uitwerking worden gebruikt;
- wanneer later meer resources, orchestration of cloudhosting nodig blijken, wordt dit besluit herzien in plaats van stilzwijgend uitgebreid.
20.10 Appsettings en options
appsettings bevat alleen niet-geheime configuratie, niet-geheime voorbeeldwaarden of lege configuratiesleutels. Securitygevoelige waarden worden via environment variables, secret stores of hostingconfiguratie geïnjecteerd.
| Configuratie | Mag in appsettings? | Toelichting |
|---|---|---|
| Featureflags zonder geheim | Ja | Geen autorisatiebron. |
| Loggingniveaus | Ja | Per omgeving verschillend. |
| Publieke basis-URL’s | Ja, indien niet geheim | Valideren per omgeving. |
| Connectionstrings met wachtwoord | Nee | Via secretmechanisme. |
| Keycloak client secret | Nee | Via secretmechanisme. |
| CSP/rate limit instellingen | Ja | Geen geheim, wel reviewen; baseline staat in hoofdstuk 20. |
| TickerQ-dashboardpad | Ja | Toegang alsnog via autorisatie/netwerkgrens. |
20.10.1 Beheerbare database-instellingen zijn geen secret store
SystemSettings en andere beheerbare configuratierecords zijn bedoeld voor niet-geheime, beheerbare applicatie-instellingen. Zij vervangen geen appsettingsbinding, environment variables of secret stores. De technische sleutelset voor beheerbare instellingen wordt via code en migratie bepaald en initieel via idempotente seeddata aangemaakt.
| Instellingstype | Bron | Regel |
|---|---|---|
| Geheim of credential | Secret store, environment variable of hostingconfiguratie | Nooit in SystemSettings, seeddata, templates of beheerbare content. |
| Niet-geheime infrastructuurconfiguratie | Appsettings/options | Valideren bij startup; niet vrij via beheerinterface tenzij expliciet als beheerbare setting ontworpen. |
| Beheerbare functionele instelling | SystemSettings of eigenaar-domein | Alleen bestaande SettingKey wijzigen binnen datatype-, bereik- en autorisatiegrenzen. |
| Featuretoggle | SiteFeatureToggles | Geen autorisatiebron; toggle schakelt functionaliteit, maar verleent geen objecttoegang. |
| Beheerbare tekst/template | Eigenaar-domein, bijvoorbeeld Admin of Communication | Sanitizing, placeholdervalidatie en history verplicht waar relevant. |
Voor iedere beheerbare instelling moet de implementatie kunnen bepalen:
- welke module eigenaar is;
- welke technische key wordt gebruikt;
- welk datatype en invoercomponent gelden;
- welke validatieregels server-side gelden;
- of wijziging history/audit vereist;
- welke defaultwaarde initieel wordt geplaatst wanneer de key ontbreekt.
Omgevingsspecifieke productiegegevens, zoals connectionstrings, client secrets, API-keys, SMTP-wachtwoorden of storage credentials, vallen altijd buiten beheerbare seeddata.
20.11 Identity provider en interne accountcontext
OefenHub gebruikt een externe identity provider, zoals de lokale Keycloak-installatie uit de ontwerpcontext, voor authenticatie. OefenHub beheert niet zelf wachtwoorden of credentialvalidatie.
| Onderdeel | Regel |
|---|---|
| Externe login | Identity provider handelt credentials af. |
| Interne accountkoppeling | OefenHub koppelt via externe identity-id aan intern account. |
| Provisioning | Nieuwe of onvolledige accounts worden server-side geïnitialiseerd. |
| Accountstatus | Intern account moet actief en bruikbaar zijn voordat reguliere applicatiecontext ontstaat. |
| Rollen | Applicatierollen en rolcontext worden server-side bepaald binnen OefenHub. |
| Tokens | Tokens of claims met gevoelige inhoud worden niet gelogd en niet in browseropslag gekopieerd. |
| Logout | OefenHub-sessie en relevante identity-providerflow worden veilig beëindigd volgens gekozen integratie. |
Als externe authenticatie slaagt maar interne provisioning faalt, ontstaat geen reguliere OefenHub-sessie. De gebruiker krijgt een veilige generieke accountfout of contactroute. Technische details komen alleen in logs met correlation-id.
20.12 Autorisatie en objecttoegang
Functionele autorisatie wordt uitgewerkt in Technisch Ontwerp: autorisatie, policies en server-side contextcontrole. Voor dit hoofdstuk gelden de infrastructuurregels.
| Regel | Betekenis |
|---|---|
| Policies centraal registreren | Policies en requirements worden voorspelbaar geregistreerd in Web/Authorization. |
| Objecttoegang server-side | Routes, ids en querystrings zijn nooit voldoende. |
| Modulecontracten controleren opnieuw | Publieke services voeren eigen autorisatie- en contextchecks uit of eisen een gevalideerde context. |
| Geen UI-only security | Verborgen knoppen vervangen geen autorisatie. |
| Access denied veilig afhandelen | Geen inhoudelijke data lekken bij geweigerde toegang. |
Voorbeelden:
GuardianResultDetail openen:
- gebruiker is ingelogd;
- actieve ouder-/voogdcontext bestaat;
- kindrelatie is actief;
- run bestaat;
- run is afgerond;
- run hoort bij het gekoppelde kind;
- pas daarna resultaatdata laden.
Docent live meekijken:
- docentcontext is actief;
- leerlingrelatie bestaat;
- niveauautorisatie valt binnen docentcontext;
- leerling heeft actieve run;
- oefening hoort bij toegestane context;
- pas daarna SignalR/live-view starten.
20.13 Rate limiting en misbruikbeperking
Rate limiting wordt in OefenHub.Web geconfigureerd met ASP.NET Core rate limiting middleware. Omdat nog niet alle concrete routes definitief zijn, legt het Technisch Ontwerp limieten vast per routecategorie. Concrete routes worden bij implementatie aan één van deze categorieën gekoppeld.
De baseline is licht: bescherming tegen misbruik en foutieve clients, geen top-tier DDoS-oplossing. Limieten gelden per ingelogde gebruiker waar mogelijk en anders per IP/cookiepartitie. Bij zwaardere acties kan aanvullend een concurrencylimiet gelden.
| Routecategorie | Partitionering | Limiet V1.0 | Queue | Opmerking |
|---|---|---|---|---|
| Publieke contentpagina's en lichte navigatie | IP | 120 requests per minuut | 0 | Alleen voor applicatiepagina's; static-file caching blijft apart. |
| Login-callback, sessieherstel en provisioning | IP + externe identity-id waar beschikbaar | 30 requests per 5 minuten | 0 | Keycloak blijft primair verantwoordelijk voor loginbeveiliging; OefenHub beschermt eigen callback/provisioning. |
| Interactieve Blazor UI-routes | Gebruiker of sessie | 300 requests per minuut | 20 | Voorkomt foutieve clients zonder normaal gebruik te blokkeren. |
| Relatie-uitnodigingen en koppelacties | Actorgebruiker + rolcontext | 20 acties per uur | 0 | Extra domeinvalidatie blijft leidend voor autorisatie en conflicten. |
| Privéberichten en systeemberichtacties | Gebruiker | 30 mutaties per 10 minuten | 0 | Lezen/navigeren valt niet onder deze mutatielimiet. |
| Meldingen/tickets aanmaken | Gebruiker of IP | 10 nieuwe tickets per 10 minuten | 0 | Beperkt spam en herhaald indienen. |
| Search/filter/list queries | Gebruiker | 60 requests per minuut | 5 | Paginering en maximale paginagrootte blijven verplicht. |
| PDF-export | Gebruiker | 5 exports per uur | 0 | Daarnaast maximaal 1 actieve PDF-export per gebruiker. |
| Beheerdermutaties | Beheerdergebruiker | 60 mutaties per minuut | 0 | Autorisatie, audit en validatie blijven leidend. |
| SignalR negotiate/connect | Gebruiker of IP | 30 pogingen per 5 minuten | 0 | Reconnectbaseline uit hoofdstuk 15 blijft gelden. |
| TickerQ-dashboard en interne tooling | Beheerdergebruiker + intern netwerk | 60 requests per minuut | 0 | Dashboard blijft intern/beheerd; rate limiting vervangt afscherming niet. |
Regels:
- rate limiting is een extra technische grens en vervangt geen autorisatie, validatie, CSRF-/antiforgerymaatregelen of domeinregels;
429-responsen zijn generiek en bevatten waar mogelijkRetry-After;- herhaalde rate-limit hits worden als securityrelevant patroon gelogd zonder payload;
- limieten worden geconfigureerd via centrale options zodat per omgeving lichte bijstelling mogelijk is zonder codewijziging;
- structurele bijstelling van categorieën of veel ruimere limieten vereist een Technisch Ontwerp-wijziging.
20.14 SignalR-security
SignalR wordt gebruikt als realtime transport, niet als bron van waarheid. Hubs mogen geen autorisatiebeslissingen baseren op clientclaims of clientgestuurde identifiers alleen.
| Onderwerp | Regel |
|---|---|
| Hubtoegang | Hubs vereisen authenticatie en passende policies. |
| Groepen | Groepslidmaatschap wordt server-side bepaald. |
| Live meekijken | Viewercontext wordt server-side gevalideerd voordat deelname aan live-updates mogelijk is. |
| Leerlingupdates | Alleen serververwerkte voortgang wordt verspreid. |
| Berichtenbadges | Onderdrukken tijdens oefening is UI-gedrag; server-side status blijft correct. |
| Reconnect | Reconnect hercontroleert context en toegang. |
| Logging | Verbindingen en fouten krijgen correlation/context zonder payloadlekken. |
Voor live meekijken geldt: SignalR verzendt updates nadat de voortgang server-side is opgeslagen. Als de SignalR-verbinding faalt, blijft de databasebron leidend.
20.15 Database- en netwerkgrenzen
De database is niet publiek internet-facing. Applicatiecomponenten benaderen de database via de geconfigureerde connectionstring.
| Onderwerp | Regel |
|---|---|
| Eén database | OefenHub gebruikt één relationele database in fase 1. |
| Eén connectionstring | Eén applicatieconnectionstring voor de module-DbContexts. |
| Schema’s | Schema’s zijn organisatorische en technische eigendomsgrenzen, geen zelfstandige securityboundary. |
| Databasegebruiker | Eén applicatiegebruiker in fase 1; verdere splitsing alleen als latere hardening. |
| Directe toegang | Geen directe externe toegang tot database voor eindgebruikers. |
| Backups | Behandelen als gevoelige data; zie beheerbeleid. |
Omdat één databasegebruiker wordt gebruikt, wordt module-isolatie niet primair door databasepermissions afgedwongen. De afdwinging gebeurt door projectgrenzen, internal implementaties, DbContext per module, publieke contracten, architecture tests en code review.
20.16 TickerQ-dashboard en interne beheerinterfaces
TickerQ wordt gebruikt voor jobs en periodieke verwerking. De webinterface voor jobs mag worden gebruikt, maar uitsluitend intern en afgeschermd.
| Onderdeel | Regel |
|---|---|
| Dashboardbeschikbaarheid | Alleen intern/beheerd; niet publiek bereikbaar. |
| Autorisatie | Alleen expliciete beheer-/operationele context. |
| Data-inhoud | Jobpayloads mogen geen credentials, tokens of onnodige persoonsgegevens bevatten. |
| Logging | JobId, JobType, CorrelationId en attempts worden technisch gelogd. |
| Failed jobs | Failed status moet beheerbaar en analyseerbaar zijn. |
| Schema | TickerQ-persistence bij voorkeur in schema scheduling. |
Als TickerQ het schema voor tabellen en dashboardconfiguratie ondersteunt, wordt dit expliciet ingesteld. Als de gekozen versie beperkingen heeft, wordt dat als Technisch Ontwerp-aandachtspunt vastgelegd en moet een veilige workaround worden gekozen.
20.17 Bestandsopslag, uploads en tijdelijke output
OefenHub beperkt vrije uploads in de eerste versie. Profielafbeeldingen zijn vooraf gedefinieerd en geen vrije upload. PDF-export en tijdelijke bestanden worden gecontroleerd verwerkt.
| Bestandstype | Securityregel |
|---|---|
| Profielafbeeldingen | Vooraf gedefinieerde set, geen vrije upload. |
| PDF-export | Tijdelijke output, veilige bestandsnaam, opnieuw genereerbaar uit databasebron. |
| Tijdelijke bestanden | Opschonen via job; opslaglocatie niet publiek browsebaar. |
| Bijlagen privéberichten | Buiten eerste versie. |
| Bijlagen meldingen | Buiten eerste versie. |
| Module-assets | Alleen vertrouwde applicatie-assets, geen vrije gebruikerupload. |
Bestandsnamen voor downloads worden gesanitized. Tijdelijke exportbestanden mogen geen autorisatie omzeilen: iedere downloadactie moet opnieuw server-side worden gecontroleerd.
20.18 Dependencybeheer en supply-chain security
OefenHub gebruikt externe libraries en frameworks zoals .NET, EF Core, Blazor, SignalR, QuestPDF, TickerQ en Keycloak-integratie. Dependencybeheer hoort onderdeel te zijn van de technische kwaliteitsgrens.
| Maatregel | Regel |
|---|---|
| Packageversies | Expliciet vastleggen en reviewen. |
| Kwetsbaarheden | Periodiek controleren via package scanning of buildchecks. |
| Updates | Securityupdates prioriteren boven cosmetische updates. |
| Licenties | Controleren of gebruik past binnen projectcontext. |
| Deprecated packages | Vermijden of vervangen met migratieplan. |
| Transitive dependencies | Meenemen in scan en review. |
Concrete tooling voor dependency scanning wordt in CI/CD en beheerbeleid vastgelegd.
20.19 Infrastructure en providerintegraties
OefenHub.Infrastructure bevat technische providerintegraties en infrastructuurhelpers die niet tot één domeinmodule behoren.
Voorbeelden:
- configuratiebinding en optionsregistratie;
- storageprovider voor tijdelijke exports;
- clock/time-provider indien niet in SharedKernel;
- mailprovider voor OefenHub-mailafhandeling waar functioneel en technisch geactiveerd;
- wrapper rond externe technische services;
- infrastructuurgerichte extension methods.
Regels:
-
Mailproviderconfiguratie bevat host, poort, credentials, afzenderidentiteit, TLS-instelling en timeoutconfiguratie uitsluitend via veilige configuratie en secrets.
-
Mailproviderfouten worden technisch gelogd met correlation-id, maar zonder volledige mailinhoud, secrets of providercredentials.
-
E-mailtemplates en mailinhoud mogen geen tokens, wachtwoorden, ruwe modulepayloads of ongeautoriseerde domeindata bevatten.
-
E-maillinks zijn transport en nooit autorisatiebewijs; iedere vervolgroute hercontroleert server-side account-, rol- en objectcontext.
-
Infrastructure bevat geen domeinregels.
-
Infrastructure kent geen UI-logica.
-
Domeinmodules gebruiken infrastructure via expliciete abstractions wanneer nodig.
-
Secrets voor infrastructureproviders komen uit veilige configuratie.
-
Infrastructure mag geen sluiproute worden om modulegrenzen te omzeilen.
20.20 Veilige foutafhandeling richting gebruiker
Gebruikers krijgen geen stacktraces, SQL-fouten, providerfouten, tokenfouten of configuratiedetails te zien.
| Situatie | Gebruikersrespons | Technische registratie |
|---|---|---|
| 403/access denied | Veilige toegang-geweigerdmelding zonder data. | Security/access-denied log met context. |
| 404/niet gevonden | Generieke niet-beschikbaarmelding. | Alleen loggen wanneer verdacht of foutpatroon. |
| 409/conflict | Functionele melding indien veilig uitlegbaar. | Domeinlog indien relevant. |
| 500/onverwacht | Generieke foutpagina met correlation-id. | Errorlog met stacktrace en veilige context. |
| Provisioningfout | Generieke account-/contactroute. | Technische log zonder identity-providergeheimen. |
| Jobfout | Geen directe gebruikersdetails tenzij flow daarom vraagt. | Schedulinglog en failed-job status. |
Foutafhandeling wordt verder beschreven in Technisch Ontwerp: logging, audit, securitylogging en technische foutafhandeling.
20.21 Logging en securitylogging vanuit infrastructuur
Hoewel logging inhoudelijk in hoofdstuk 19 staat, gelden voor infrastructuur deze technische randvoorwaarden:
| Randvoorwaarde | Regel |
|---|---|
| Correlation-id | Iedere request en job heeft herleidbare correlation. |
| Request-id | Technische request-id wordt gekoppeld aan correlation waar mogelijk. |
| Geen secrets | Headers, tokens, cookies en connectionstrings worden niet gelogd. |
| Geen payloaddump | Formulieren, antwoorden, berichten en exports worden niet integraal gelogd. |
| Securityevents | Verdachte patronen, access denied en misbruikpogingen worden voldoende herleidbaar geregistreerd. |
| Jobevents | Job lifecycle krijgt JobId, JobType, attempt en resultstatus. |
Securitylogging mag niet afhankelijk zijn van een apart securityproject. Het wordt technisch gerealiseerd via middleware, authorization handlers, domeinservices en schedulingcomponenten.
20.22 Deployment- en hostingrandvoorwaarden
Deploymentdetails worden uitgewerkt in Technisch Ontwerp: beheerbeleid, monitoring, backup, restore en operatie. Voor security gelden alvast deze randvoorwaarden.
| Onderwerp | Regel |
|---|---|
| Build artifacts | Geen secrets in artifacts. |
| Configuratie | Omgevingsspecifiek, niet hardcoded. |
| Migrations | Bewust uitvoeren met rollback-/herstelplan. |
| TickerQ | Persistentie en dashboardconfiguratie controleren na deployment. |
| Keycloak/identity provider | Bereikbaarheid en configuratie als smoke test. |
| Database | Connectivity, schema en migrationstatus controleren. |
| HTTPS/certificaten | Geldigheid en configuratie controleren. |
| Securityheaders | Via smoke/securitycheck controleren. |
20.23 Teststrategie voor security en infrastructuur
Securitytests worden niet beperkt tot handmatige controle. Minimaal worden de volgende testsoorten voorzien.
| Testtype | Doel |
|---|---|
| Unit tests | Optionsvalidatie, policyrequirements, sanitizinghelpers, veilige bestandsnaamlogica. |
| Integration tests | Authenticated/unauthenticated routes, policies, access denied, cookies, headers. |
| Architecture tests | Geen Web-reference vanuit modules, geen directe cross-module entities, geen verboden projectreferences. |
| Configuration tests | Productieconfiguratie mist geen verplichte waarden en bevat geen development defaults. |
| Security header tests | Baseline headers aanwezig in niet-lokale omgevingen. |
| SignalR tests | Hubtoegang en reconnect hercontroleren autorisatie. |
| Job security tests | TickerQ-dashboard afgeschermd, jobpayload veilig, failed jobs herleidbaar. |
| Dependency scanning | Bekende kwetsbaarheden in packages signaleren. |
20.24 Implementatiechecklist
Bij implementatie of wijziging van security-/infrastructuurgedrag moet minimaal worden gecontroleerd:
- Is de wijziging in het juiste project geplaatst en niet in een kunstmatig securityproject?
- Zijn secrets buiten broncode en logs gebleven?
- Zijn optionsclasses gevalideerd bij startup?
- Is de middlewarevolgorde passend bij Blazor, SignalR, authenticatie en autorisatie?
- Zijn securityheaders actief in niet-lokale omgevingen?
- Is de CSP-baseline getest met Blazor, SignalR, MudBlazor, fonts, images en PDF-downloads?
- Zijn cookies veilig geconfigureerd?
- Is browseropslag beperkt tot niet-gevoelige technische voorkeuren?
- Worden access-denied en verdachte toegangspogingen veilig gelogd?
- Is de TickerQ-webinterface intern en autorisatiebeperkt?
- Bevatten jobpayloads geen secrets of onnodige persoonsgegevens?
- Zijn database, backups en tijdelijke exports niet publiek bereikbaar?
- Is er een test of smoke check voor de wijziging?
- Is Aspire beperkt tot development-only ondersteuning en gebruikt het dezelfde optionsvalidatie als andere omgevingen?
20.25 Implementatieverificaties
De volgende punten moeten tijdens implementatie of detailontwerp nog concreet worden gecontroleerd:
| Punt | Te controleren |
|---|---|
| CSP-detailconfiguratie | Toetsen dat de vastgelegde CSP-baseline werkt met de gekozen Blazorversie, SignalR, fonts, icons en componentlibraries. |
| TickerQ-schema | Of TickerQ alle tabellen en dashboardconfiguratie onder schema scheduling kan plaatsen. |
| TickerQ-dashboard | Hoe interne netwerktoegang en autorisatie exact worden gecombineerd. |
| Rate limits | Toetsen dat concrete routes correct zijn gekoppeld aan de vastgelegde routecategorieën en limieten. |
| Securityheaders | Definitieve headerwaarden per omgeving. |
| Secretbaseline Docker V1.0 | Toetsen dat secrets via Docker Compose secrets, read-only secretbestanden of, bij Swarm, Docker/Portainer secrets buiten repository en images blijven. |
| Dependency scanning | Tooling en CI/CD-integratie. |
| Securityevent-persistentie | Of verdachte toegangspogingen alleen technisch gelogd worden of ook in domein-/beheerbare tabellen moeten landen. |
| HSTS preload | Pas beslissen na domein- en certificaatstrategie. |
| Antiforgery | Exacte toepassing afhankelijk van gekozen Blazor-hostingmodel en formulier/endpointroutes. |