Skip to main content

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:

OnderwerpPrimaire plaats
Authenticatie-integratie en accountkoppelingOefenHub.Identity
Rolcontext, policies en server-side autorisatiecontroleOefenHub.Authorization
Middleware, headers, cookies, rate limiting en request pipelineOefenHub.Web
Hosting-, netwerk-, configuratie- en providerintegratieOefenHub.Infrastructure en hostingomgeving
Jobtoegang, jobstatussen, TickerQ-dashboard en retrybeheerOefenHub.Scheduling
Domeinspecifieke toegangscontrole en audit/historyEigenaar-module van het betreffende domein
Technische logging, securitylogging en foutafhandelingTechnisch Ontwerp: logging, audit, securitylogging en technische foutafhandeling
Privacy, retentie en anonimiseringTechnisch 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.

PrincipeUitwerking
Server-side vertrouwenAutorisatie, rolcontext, objecttoegang en datatoegang worden server-side bepaald. Clientstate, routes, querystrings, zichtbare knoppen of browseropslag zijn nooit autoriserend.
Eén applicatie, meerdere grenzenOefenHub is één deploybare applicatie, maar modulegrenzen, DbContexts, schemas en publieke contracten beperken ongewenste koppeling.
Geen securitydoorbraak via gemakUI-compositie, readmodels, caching, SignalR, PDF-export en jobs mogen de server-side autorisatiegrenzen niet verruimen.
Geen credentials in OefenHubWachtwoorden, credentialvalidatie en identity-providerinterne gegevens blijven buiten OefenHub. OefenHub verwerkt alleen de uitkomst van externe authenticatie en de eigen applicatiecontext.
Secrets buiten codeSecrets, connectionstrings, client secrets, certificaatwachtwoorden en tokens staan niet in broncode of versiebeheer.
Securityconfiguratie als codeHeaders, middleware, rate limits, cookiebeleid en environment-afhankelijke opties worden expliciet geconfigureerd en gevalideerd.
Minimaal lekkenFoutmeldingen aan gebruikers zijn generiek. Technische details komen alleen in beveiligde logs met correlation-id.
HerleidbaarheidSecurityrelevante 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.

OmgevingDoelSecurity-uitgangspunt
LocalLokale ontwikkelingLokale secrets via veilige developermechanismen, geen productiegegevens, debugmogelijkheden toegestaan.
DevelopmentGedeelde ontwikkelomgevingGeen productiegegevens, beperkte externe toegang, logging mag uitgebreider zijn maar zonder secrets of tokens.
TestTechnische en functionele verificatieRealistische configuratie, testdata, geen productiecredentials, migrations en jobs testbaar.
AcceptancePre-productieacceptatieProductie-achtige securityconfiguratie, beperkte toegang, representatieve maar gecontroleerde data.
ProductionProductiegebruikStrikte 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 Development of Local is.

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.

OnderdeelBaselineafspraakValidatie
ScopeAspire wordt alleen gebruikt voor lokale ontwikkeling en eventueel technische smoke checks.Niet-lokale deployment kan OefenHub.Web starten zonder Aspire AppHost.
ProjectgrensEen eventuele OefenHub.AppHost of vergelijkbare development host staat buiten domein-, applicatie- en datamodules.Productieprojecten refereren niet naar de development host.
AfhankelijkhedenAspire 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.
ConfiguratiebindingDevelopment gebruikt dezelfde optionsclasses, configuratiesleutels en startupvalidatie als andere omgevingen.Een configuratiefout faalt in development op dezelfde validatieklasse als buiten development.
SecretsAspire 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.
DataLokale databases, volumes en testdata zijn developmentdata en geen bron van waarheid.Productiedata, backups en exports worden niet via Aspire-development ingericht.
ObservabilityAspire mag lokale observability en dashboardinformatie tonen voor ontwikkelaars.Operationele loggingbaseline blijft Serilog + Seq; Aspire vervangt geen productiebeheer of monitoring.
DocumentatieAfwijkingen 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.

ProjectSecurityverantwoordelijkheid
OefenHub.WebMiddlewarepipeline, HTTPS/HSTS, securityheaders, cookies, antiforgery waar relevant, rate limiting, foutpagina’s, Blazor/Razor boundaries, TickerQ-dashboard-afscherming.
OefenHub.IdentityKoppeling tussen identity provider en intern account, provisioning, accountstatus, externe identity-id’s, geen credentialbeheer.
OefenHub.AuthorizationPolicies, rolcontext, objecttoegang, server-side contextcontrole, access-denied afhandeling.
OefenHub.InfrastructureTechnische providers, configuratiebinding, secret-/storage-integratie, externe services, infrastructuurhelpers.
OefenHub.SchedulingJobtoegang, TickerQ-configuratie, interne jobinterface, joblogging, retrybeleid en failed-job beheer.
DomeinmodulesDomeineigen 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.

StapDoel
Exception handlingCentrale veilige foutafhandeling en correlation-id borging.
HTTPS redirectionHTTP-verkeer naar HTTPS sturen buiten lokale uitzonderingen.
HSTSBrowsers instrueren om HTTPS te gebruiken in productie.
Security headersCSP, framebeleid, content-type bescherming, referrerbeleid en permissionsbeleid toepassen.
Static filesAlleen bedoelde statische bestanden leveren met passende caching en content-type bescherming.
RoutingRoutes bepalen zonder autorisatiebeslissing op basis van clientstate.
Rate limitingMisbruik en brute-forceachtige patronen beperken waar relevant.
AuthenticationIdentity-provideruitkomst verwerken.
AuthorizationPolicies en server-side autorisatie toepassen.
AntiforgeryFormulieren/endpoints beschermen waar het hostingmodel dit vereist.
Blazor/Razor endpointsUI en interactieve componenten hosten.
SignalR hubsAlleen geautoriseerde realtimeverbindingen toestaan.
TickerQ dashboardAlleen 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.

MaatregelRegel
HTTPSVerplicht voor niet-lokale omgevingen.
HSTSIn productie actief, met passende max-age en alleen wanneer TLS correct is ingericht.
Secure cookiesAuthenticatie- en sessiegerelateerde cookies zijn Secure.
Mixed contentNiet toegestaan in productiepagina’s.
WebSockets/SignalRAlleen via beveiligde transporten in productie.
Interne dashboardsAlleen 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 / beleidDoelBaseline
Content-Security-PolicyBeperkt toegestane script-, style-, image-, connect- en framebronnen.Alleen noodzakelijke bronnen toestaan; SignalR/WebSocket expliciet meenemen.
Strict-Transport-SecurityDwingt HTTPS-gebruik af bij browsers.Productie, na TLS-validatie.
X-Content-Type-OptionsVoorkomt MIME-sniffing.nosniff.
Referrer-PolicyBeperkt referrerlekken.Strikt beleid, bijvoorbeeld strict-origin-when-cross-origin of strenger.
Permissions-PolicyBeperkt browserfeatures zoals camera, microfoon, geolocation.Alleen toestaan wat OefenHub gebruikt; standaard uit.
FramebeleidBeperkt framing/clickjacking.Via CSP frame-ancestors; eventueel aanvullende legacy-header.
Cache-ControlVoorkomt 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-src gebruikt 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-src staat in productie alleen self en beveiligde WebSocketverbindingen toe; lokale development mag ws: 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.

OpslagToegestaanNiet toegestaan
AuthenticatiecookieAlleen via identity-/authmiddleware, secure en httpOnly waar mogelijk.Eigen wachtwoorden, tokens of identity-providerinterne gegevens opslaan.
Technische toegankelijkheidscookieVoor pre-login renderingvoorkeuren zoals contrast of dyslexielettertype.Persoonsgegevens, rollen, autorisaties, account-id’s.
Once-per-browser notificatieonderdrukkingAlleen niet-persoonsgebonden notificatie-id/status.Server-side seen-status of autorisatie vervangen.
Local/session storageAlleen 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.

SecrettypeVoorbeeldenRegels
DatabaseConnectionstring, wachtwoordVia environment/secret store; niet loggen.
Identity providerClient secret, realm/adminwaarden indien gebruiktAlleen via veilige configuratie; niet tonen aan gebruiker.
Signing/encryptionCertificaatwachtwoorden, keysNiet in appsettings in repository; rotatieplan nodig.
Storage/exportBestandsopslagcredentialsAlleen omgeving-/secretgebonden.
SMTP/externe services indien toekomstig nodigAPI keys, wachtwoordenAlleen 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.

OmgevingSecretbaseline V1.0
Local/development.NET user secrets, lokale secretbestanden of lokale environmentvariabelen buiten repository; geen productiesecrets.
Test/acceptatie in DockerDocker Compose secrets of read-only gemounte secretbestanden buiten repository.
Productie Docker zonder SwarmDocker Compose secrets of read-only gemounte secretbestanden buiten repository, beschikbaar als bestanden in de container.
Productie Docker Swarm/Portainer SwarmDocker/Portainer Swarm secrets wanneer Swarm daadwerkelijk wordt gebruikt.
Kubernetes of cloud laterKubernetes 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.

ConfiguratieMag in appsettings?Toelichting
Featureflags zonder geheimJaGeen autorisatiebron.
LoggingniveausJaPer omgeving verschillend.
Publieke basis-URL’sJa, indien niet geheimValideren per omgeving.
Connectionstrings met wachtwoordNeeVia secretmechanisme.
Keycloak client secretNeeVia secretmechanisme.
CSP/rate limit instellingenJaGeen geheim, wel reviewen; baseline staat in hoofdstuk 20.
TickerQ-dashboardpadJaToegang 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.

InstellingstypeBronRegel
Geheim of credentialSecret store, environment variable of hostingconfiguratieNooit in SystemSettings, seeddata, templates of beheerbare content.
Niet-geheime infrastructuurconfiguratieAppsettings/optionsValideren bij startup; niet vrij via beheerinterface tenzij expliciet als beheerbare setting ontworpen.
Beheerbare functionele instellingSystemSettings of eigenaar-domeinAlleen bestaande SettingKey wijzigen binnen datatype-, bereik- en autorisatiegrenzen.
FeaturetoggleSiteFeatureTogglesGeen autorisatiebron; toggle schakelt functionaliteit, maar verleent geen objecttoegang.
Beheerbare tekst/templateEigenaar-domein, bijvoorbeeld Admin of CommunicationSanitizing, 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.

OnderdeelRegel
Externe loginIdentity provider handelt credentials af.
Interne accountkoppelingOefenHub koppelt via externe identity-id aan intern account.
ProvisioningNieuwe of onvolledige accounts worden server-side geïnitialiseerd.
AccountstatusIntern account moet actief en bruikbaar zijn voordat reguliere applicatiecontext ontstaat.
RollenApplicatierollen en rolcontext worden server-side bepaald binnen OefenHub.
TokensTokens of claims met gevoelige inhoud worden niet gelogd en niet in browseropslag gekopieerd.
LogoutOefenHub-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.

RegelBetekenis
Policies centraal registrerenPolicies en requirements worden voorspelbaar geregistreerd in Web/Authorization.
Objecttoegang server-sideRoutes, ids en querystrings zijn nooit voldoende.
Modulecontracten controleren opnieuwPublieke services voeren eigen autorisatie- en contextchecks uit of eisen een gevalideerde context.
Geen UI-only securityVerborgen knoppen vervangen geen autorisatie.
Access denied veilig afhandelenGeen 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.

RoutecategoriePartitioneringLimiet V1.0QueueOpmerking
Publieke contentpagina's en lichte navigatieIP120 requests per minuut0Alleen voor applicatiepagina's; static-file caching blijft apart.
Login-callback, sessieherstel en provisioningIP + externe identity-id waar beschikbaar30 requests per 5 minuten0Keycloak blijft primair verantwoordelijk voor loginbeveiliging; OefenHub beschermt eigen callback/provisioning.
Interactieve Blazor UI-routesGebruiker of sessie300 requests per minuut20Voorkomt foutieve clients zonder normaal gebruik te blokkeren.
Relatie-uitnodigingen en koppelactiesActorgebruiker + rolcontext20 acties per uur0Extra domeinvalidatie blijft leidend voor autorisatie en conflicten.
Privéberichten en systeemberichtactiesGebruiker30 mutaties per 10 minuten0Lezen/navigeren valt niet onder deze mutatielimiet.
Meldingen/tickets aanmakenGebruiker of IP10 nieuwe tickets per 10 minuten0Beperkt spam en herhaald indienen.
Search/filter/list queriesGebruiker60 requests per minuut5Paginering en maximale paginagrootte blijven verplicht.
PDF-exportGebruiker5 exports per uur0Daarnaast maximaal 1 actieve PDF-export per gebruiker.
BeheerdermutatiesBeheerdergebruiker60 mutaties per minuut0Autorisatie, audit en validatie blijven leidend.
SignalR negotiate/connectGebruiker of IP30 pogingen per 5 minuten0Reconnectbaseline uit hoofdstuk 15 blijft gelden.
TickerQ-dashboard en interne toolingBeheerdergebruiker + intern netwerk60 requests per minuut0Dashboard 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 mogelijk Retry-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.

OnderwerpRegel
HubtoegangHubs vereisen authenticatie en passende policies.
GroepenGroepslidmaatschap wordt server-side bepaald.
Live meekijkenViewercontext wordt server-side gevalideerd voordat deelname aan live-updates mogelijk is.
LeerlingupdatesAlleen serververwerkte voortgang wordt verspreid.
BerichtenbadgesOnderdrukken tijdens oefening is UI-gedrag; server-side status blijft correct.
ReconnectReconnect hercontroleert context en toegang.
LoggingVerbindingen 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.

OnderwerpRegel
Eén databaseOefenHub gebruikt één relationele database in fase 1.
Eén connectionstringEén applicatieconnectionstring voor de module-DbContexts.
Schema’sSchema’s zijn organisatorische en technische eigendomsgrenzen, geen zelfstandige securityboundary.
DatabasegebruikerEén applicatiegebruiker in fase 1; verdere splitsing alleen als latere hardening.
Directe toegangGeen directe externe toegang tot database voor eindgebruikers.
BackupsBehandelen 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.

OnderdeelRegel
DashboardbeschikbaarheidAlleen intern/beheerd; niet publiek bereikbaar.
AutorisatieAlleen expliciete beheer-/operationele context.
Data-inhoudJobpayloads mogen geen credentials, tokens of onnodige persoonsgegevens bevatten.
LoggingJobId, JobType, CorrelationId en attempts worden technisch gelogd.
Failed jobsFailed status moet beheerbaar en analyseerbaar zijn.
SchemaTickerQ-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.

BestandstypeSecurityregel
ProfielafbeeldingenVooraf gedefinieerde set, geen vrije upload.
PDF-exportTijdelijke output, veilige bestandsnaam, opnieuw genereerbaar uit databasebron.
Tijdelijke bestandenOpschonen via job; opslaglocatie niet publiek browsebaar.
Bijlagen privéberichtenBuiten eerste versie.
Bijlagen meldingenBuiten eerste versie.
Module-assetsAlleen 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.

MaatregelRegel
PackageversiesExpliciet vastleggen en reviewen.
KwetsbaarhedenPeriodiek controleren via package scanning of buildchecks.
UpdatesSecurityupdates prioriteren boven cosmetische updates.
LicentiesControleren of gebruik past binnen projectcontext.
Deprecated packagesVermijden of vervangen met migratieplan.
Transitive dependenciesMeenemen 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.

SituatieGebruikersresponsTechnische registratie
403/access deniedVeilige toegang-geweigerdmelding zonder data.Security/access-denied log met context.
404/niet gevondenGenerieke niet-beschikbaarmelding.Alleen loggen wanneer verdacht of foutpatroon.
409/conflictFunctionele melding indien veilig uitlegbaar.Domeinlog indien relevant.
500/onverwachtGenerieke foutpagina met correlation-id.Errorlog met stacktrace en veilige context.
ProvisioningfoutGenerieke account-/contactroute.Technische log zonder identity-providergeheimen.
JobfoutGeen 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:

RandvoorwaardeRegel
Correlation-idIedere request en job heeft herleidbare correlation.
Request-idTechnische request-id wordt gekoppeld aan correlation waar mogelijk.
Geen secretsHeaders, tokens, cookies en connectionstrings worden niet gelogd.
Geen payloaddumpFormulieren, antwoorden, berichten en exports worden niet integraal gelogd.
SecurityeventsVerdachte patronen, access denied en misbruikpogingen worden voldoende herleidbaar geregistreerd.
JobeventsJob 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.

OnderwerpRegel
Build artifactsGeen secrets in artifacts.
ConfiguratieOmgevingsspecifiek, niet hardcoded.
MigrationsBewust uitvoeren met rollback-/herstelplan.
TickerQPersistentie en dashboardconfiguratie controleren na deployment.
Keycloak/identity providerBereikbaarheid en configuratie als smoke test.
DatabaseConnectivity, schema en migrationstatus controleren.
HTTPS/certificatenGeldigheid en configuratie controleren.
SecurityheadersVia smoke/securitycheck controleren.

20.23 Teststrategie voor security en infrastructuur

Securitytests worden niet beperkt tot handmatige controle. Minimaal worden de volgende testsoorten voorzien.

TesttypeDoel
Unit testsOptionsvalidatie, policyrequirements, sanitizinghelpers, veilige bestandsnaamlogica.
Integration testsAuthenticated/unauthenticated routes, policies, access denied, cookies, headers.
Architecture testsGeen Web-reference vanuit modules, geen directe cross-module entities, geen verboden projectreferences.
Configuration testsProductieconfiguratie mist geen verplichte waarden en bevat geen development defaults.
Security header testsBaseline headers aanwezig in niet-lokale omgevingen.
SignalR testsHubtoegang en reconnect hercontroleren autorisatie.
Job security testsTickerQ-dashboard afgeschermd, jobpayload veilig, failed jobs herleidbaar.
Dependency scanningBekende 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:

PuntTe controleren
CSP-detailconfiguratieToetsen dat de vastgelegde CSP-baseline werkt met de gekozen Blazorversie, SignalR, fonts, icons en componentlibraries.
TickerQ-schemaOf TickerQ alle tabellen en dashboardconfiguratie onder schema scheduling kan plaatsen.
TickerQ-dashboardHoe interne netwerktoegang en autorisatie exact worden gecombineerd.
Rate limitsToetsen dat concrete routes correct zijn gekoppeld aan de vastgelegde routecategorieën en limieten.
SecurityheadersDefinitieve headerwaarden per omgeving.
Secretbaseline Docker V1.0Toetsen dat secrets via Docker Compose secrets, read-only secretbestanden of, bij Swarm, Docker/Portainer secrets buiten repository en images blijven.
Dependency scanningTooling en CI/CD-integratie.
Securityevent-persistentieOf verdachte toegangspogingen alleen technisch gelogd worden of ook in domein-/beheerbare tabellen moeten landen.
HSTS preloadPas beslissen na domein- en certificaatstrategie.
AntiforgeryExacte toepassing afhankelijk van gekozen Blazor-hostingmodel en formulier/endpointroutes.