Technische en organisatorische maatregelen
Hoort bij de verwerkersovereenkomst. Elke maatregel hieronder is op de genoemde datum in de code of op de live server nagekeken; de bron staat erbij. Wijzigingen krijgen een nieuwe versie met ingangsdatum (zie verwerkersovereenkomst art. 5).
| Onderwerp | Maatregel | Bron / controle (3 nov 2026) |
|---|---|---|
| Verbinding | Alleen HTTPS; HSTS 1 jaar inclusief subdomeinen; onveilige verzoeken worden opgewaardeerd | live response headers cavely.nl |
| Browser | Content-Security-Policy default-src 'self' (geen scripts, stijlen of fonts van derden); inbouwen alleen op toegestane salonwebsites (frame-ancestors); nosniff, strikte referrer, camera/microfoon/locatie uit | live headers; public/index.php |
| Scheiding per salon | De salon volgt uit de ingelogde gebruiker, nooit uit de URL; elke databasevraag is per salon afgebakend | src/Admin.php, src/Booking.php; tests RolesTest/AppTest |
| Rollen | Eigenaar, balie, medewerker; per route op de server gecontroleerd, onbekende routes alleen eigenaar; medewerker alleen eigen agenda; rol wordt bij elk verzoek opnieuw gelezen | src/Admin.php POLICY; RolesTest |
| Wachtwoorden | Alleen opgeslagen als niet-terug te rekenen hash (PHP password_hash, bcrypt) | src/Admin.php |
| Tweestapsverificatie | Beschikbaar voor elke gebruiker (TOTP-app); geheimen versleuteld (AES-256-GCM) met een sleutel buiten de database; herstelcodes alleen als HMAC; elke code één keer bruikbaar | src/Totp.php, src/Admin.php; MfaTest, race-test op MySQL |
| Sessies | Willekeurige 256-bit sleutel in een HttpOnly, Secure, SameSite=Strict cookie; alleen de hash in de database; 12 uur geldig; CSRF-token per sessie op elke wijziging | src/Admin.php |
| Inlogmisbruik | Na 5 mislukte pogingen per account of per adres 15 minuten geblokkeerd; IP-adressen alleen als afgeleide waarde, na 24 uur opgeruimd | src/RateLimit.php, bin/cron.php |
| Klantlinks | Persoonlijke links in mails zijn willekeurig; alleen de hash staat in de database; de link zelf verdwijnt uit de verzendwachtrij na verzending | src/Booking.php, src/Outbox.php |
| Logboek | Elke wijziging in het beheer en elke export: wie, wat, wanneer, met uitkomst; vóór de wijziging vastgelegd, erna afgerond | src/Admin.php audit; AuditTest |
| Gelijktijdigheid | Dubbele boekingen voorkomen met een vergrendeling per medewerker; bewezen met gelijktijdige pogingen op de productiedatabase | docs/OPERATIONS.md gate 5 |
| Geen open- of kliktracking; meldingen over niet-bezorgde mail alleen met een ondertekende verwijzing geaccepteerd | src/SmtpMailer.php, src/MailEvents.php | |
| Reservekopieën | Elke nacht; versleuteld (AES-256-GCM met RSA-sleutelomhulling) voordat ze worden opgeslagen; 30 dagen bewaard op een schijf van OwlyVision in Nederland; elke nacht automatisch teruggezet in een losse testdatabase en vergeleken | tools/backup-db.ps1, tools/backup-nightly.ps1, backup.log |
| Kopie elk kwartier (sinds 4 nov 2026) | Elke 15 minuten haalt een aparte server van OwlyVision in Groningen een consistente kopie op via een sleutel die op de server alleen die kopie mag maken (de databasewachtwoorden blijven op de server); versleuteld met age (X25519) voordat hij wordt opgeslagen, nooit onversleuteld op schijf; elke kopie wordt meteen teruggezet in een tijdelijke database in het werkgeheugen en per tabel op aantal rijen vergeleken; 7 dagen bewaard; een melding als de laatste geslaagde controle ouder is dan 45 minuten | tools/standby/verify-copy.sh, ~/bin/cavely-dump.sh op de server |
| Bewaking | Elke 15 minuten van buitenaf: pagina's, geplande taken, verzending; bij een storing direct een melding aan OwlyVision | tools/watchdog.ps1, bin/health.php |
| Uitrol | Elke release wordt na upload byte voor byte vergeleken (SHA-256) en de pagina's worden live geladen; geheimen staan versleuteld buiten de code en nooit in een release | tools/deploy.ps1 |
| Foutmeldingen | Logregels bevatten geen tokens of klantgegevens, alleen vaste routenamen | src/App.php |
| Toegang OwlyVision | Alleen wie Cavely beheert, via een SSH-sleutel; alleen voor support, storingen of herstel; geen klantgegevens naar AI-diensten | werkafspraak; CLAUDE.md |
Bekende beperkingen (eerlijk vermeld)
- Tweestapsverificatie is niet verplicht. Een eigenaar zonder tweede stap kan met alleen een wachtwoord bij de gegevens van de hele salon; we raden het daarom sterk aan.
- De sleutels van de reservekopieën en de herstelprocedure liggen bij één persoon (OwlyVision). Een procedure voor langdurige afwezigheid is nog niet vastgelegd.
- De bewakingscontrole draait vanaf een machine van OwlyVision, niet vanaf een onafhankelijke dienst.