3.4 KiB
3.4 KiB
Security beleid
Kwetsbaarheden melden
Gevonden een beveiligingsprobleem? Stuur een e-mail naar de systeembeheerder van jouw scholengroep.
Voeg zo veel mogelijk detail toe: stappen om te reproduceren, impact, en eventueel een proof-of-concept.
Publiceer kwetsbaarheden niet publiek voordat ze zijn opgelost.
Beveiligingsmaatregelen in deze applicatie
Authenticatie
- Primaire login via Microsoft Entra ID (Azure AD) — geen wachtwoorden opgeslagen voor gewone gebruikers
- Superadmin wachtwoord gehasht met scrypt (sterk geheugenintensief algoritme)
- OAuth2 state parameter validatie — beschermt tegen CSRF in OAuth flow
?next=redirect parameter gevalideerd — beschermt tegen open redirect aanvallen- Session cookies:
HttpOnly,Secure(HTTPS),SameSite=Lax
Rate limiting
| Endpoint | Limiet |
|---|---|
Alle /auth/* routes |
10 per minuut per IP |
| Superadmin login | 10/min + 30/uur per IP |
| API endpoints | 120 per minuut per IP |
| Doelen upload | 5 per minuut per IP |
| Setup endpoint | 5 per minuut per IP |
Rate limiting via Redis (persistent over meerdere workers).
Nginx voegt een extra laag rate limiting toe vóór Flask.
HTTP Security headers
Via Flask-Talisman + Nginx:
Content-Security-Policy— nonce-based, geen unsafe-inline scriptsStrict-Transport-Security— HSTS 1 jaar, incl. subdomainsX-Frame-Options: DENY— clickjacking preventieX-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-originPermissions-Policy— geen toegang tot camera/microfoon/locatieform-action: 'self'— voorkomt form hijackingbase-uri: 'self'— voorkomt base tag injectionobject-src: 'none'— geen Flash of plugins
Autorisatie
- Rolgebaseerde toegangscontrole (superadmin → scholengroep_ict → school_ict → director → teacher)
- Elke API route heeft expliciete rolauthenticatie decorator
- School-isolatie: gebruikers kunnen enkel data van hun eigen school zien
- Auditlog van alle beheerhandelingen
Database
- Parameterized queries via SQLAlchemy ORM — geen raw SQL met gebruikersinput
- Non-root database gebruiker
- PostgreSQL container niet publiek blootgesteld (intern Docker netwerk)
Infrastructuur
- Flask draait als non-root gebruiker (
appuser) in Docker container - Read-only volume mount voor doelen JSON bestanden
- Redis beveiligd met wachtwoord
- Backend enkel bereikbaar via
127.0.0.1(niet publiek) - Nginx als reverse proxy met request size limiting en timeouts (Slowloris bescherming)
Dependency updates
Controleer regelmatig op kwetsbaarheden in dependencies:
pip install pip-audit
pip-audit -r backend/requirements.txt
Python base image: pin op specifieke patch versie in Dockerfile.
Controleer updates op: https://hub.docker.com/_/python
Checklist voor nieuwe deployment
SECRET_KEYgegenereerd metpython3 -c "import secrets; print(secrets.token_hex(32))"POSTGRES_PASSWORDsterk en uniekREDIS_PASSWORDingesteldBASE_URLcorrect ingesteld op HTTPS URL- SSL/TLS certificaat aanwezig (Let's Encrypt via Certbot)
- Microsoft Entra ID app registratie correct geconfigureerd
- Superadmin wachtwoord ingesteld via
/auth/setup(min. 12 tekens) /auth/setupendpoint niet meer toegankelijk na setup (wordt automatisch geblokkeerd)- Firewall: enkel poorten 80 en 443 publiek open