Project: Van Dam Juweliers - Project Mijn Cyberweerbare Zaak
Van Dam Juweliers - Werkpakket Project Mijn Cyberweerbare Zaak
CODE SNIPPETS
W. Zantinge
Binnen de digitale veiligheidsinspectie is eerst een externe technische inventarisatie uitgevoerd op de inrichting van interne informatiestromen, toegangsstructuren, backupvolwassenheid en continuïteitsrisico’s. Daarbij lag de nadruk op het identificeren van veelvoorkomende zwakke plekken zoals te brede gebruikersrechten, onvoldoende scheiding tussen operationele en autorisatiebeheer, onduidelijke backup retentie, gebrek aan periodieke hersteltests en onvoldoende borging van mutaties in accounts bij rolwijziging of uitdiensttreding. Een externe digitale veiligheidsinspectie is uitgevoerd, gericht op het in kaart brengen van kwetsbaarheden, afhankelijkheden en organisatorische zwakke plekken rond data, toegangsrechten en continuïteit. Denk daarbij aan onvoldoende vastgelegde back-uproutines, onduidelijkheid over retentie en hersteltests, ontbreken van eenduidige MFA protocollen, te brede gebruikersrechten, gebrekkige periodieke controle en onvoldoende procesmatige borging bij uitdiensttreding of functiewijziging. Dit is uitgevoerd middels een opmaat gemaakte technische inventarisatie van systemen en dataclassificatie.
Technische inventarisatie van systemen en dataclassificatie.
from dataclasses import dataclass, field
from typing import List, Optional
import datetime
@dataclass
class System:
name: str
owner: str
criticality: str
data_types: List[str]
rto_hours: int
rpo_hours: int
backup_required: bool
mfa_required: bool
dependencies: List[str] = field(default_factory=list)
last_reviewed: Optional[datetime.date] = None
def validate_systems(systems: List[System]) -> bool:
names = [s.name for s in systems]
if len(names) != len(set(names)):
raise ValueError("Duplicate system names detected")
for s in systems:
if s.rpo_hours > s.rto_hours:
raise ValueError(f"RPO > RTO in {s.name}")
if s.criticality in ("high", "critical") and not s.mfa_required:
raise ValueError(f"MFA required for {s.name}")
return True
systems = [
System(
name="ERP / orderadministratie",
owner="Operations",
criticality="high",
data_types=["klantgegevens", "ordernummers", "factuurinformatie"],
rto_hours=8,
rpo_hours=24,
backup_required=True,
mfa_required=True,
dependencies=[],
last_reviewed=datetime.date(year, month, day)
),
System(
name="bestandsopslag interne documenten",
owner="Directie",
criticality="high",
data_types=["financiële documenten", "personeelsinformatie", "leveranciersafspraken"],
rto_hours=12,
rpo_hours=24,
backup_required=True,
mfa_required=True,
dependencies=["ERP / orderadministratie"],
last_reviewed=datetime.date(year, month, day)
),
System(
name="e-mailomgeving",
owner="Administratie",
criticality="medium",
data_types=["communicatie", "offertes", "bijlagen"],
rto_hours=4,
rpo_hours=12,
backup_required=True,
mfa_required=True,
dependencies=[],
last_reviewed=datetime.date(year, month, day)
),
]
if __name__ == "__main__":
validate_systems(systems)
for sys in systems:
print(f"{sys.name:40s} {sys.criticality:8s} RTO:{sys.rto_hours}h RPO:{sys.rpo_hours}h")
W. Stepanian
In dit onderdeel zijn structurele beheersmaatregelen uitgewerkt en overgedragen. Omdat de uitvoering niet bestond uit onbeperkte beheertoegang in alle klantsystemen, is het technisch werk in dit dossier het best te omschrijven als: analyse, ontwerp, parameterisering, overdraagbare configuratievoorstellen, validatiestappen en implementatiebegeleiding. Verder is in de inspectie gekeken naar de mate waarin veiligheidsmaatregelen daadwerkelijk procesmatig zijn geborgd. Het gaat dan niet alleen om de theoretische aanwezigheid van een back-up of een account, maar om de vraag of vastligt wie verantwoordelijk is, hoe vaak controles plaatsvinden, wanneer wordt getest en hoe afwijkingen worden opgevolgd. Binnen de context van dit project lag de nadruk daarbij op twee kerndomeinen: betrouwbare back-up- en herstelinrichting, en beheersing van MFA/veilige toegang. Deze keuze was logisch, omdat beide domeinen direct raken aan de weerbaarheid tegen dataverlies, uitval, ransomware-impact en onbevoegde toegang.
De laatste projectfase bestond uit een gestructureerde review van de opgeleverde stukken. Dit onderdeel heeft circa 10 uur in beslag genomen en was gericht op de vraag of de projectoutput inhoudelijk correct, praktisch bruikbaar en intern consistent was. Deze fase is van belang omdat cybermaatregelen alleen effectief zijn als de uitwerking nauwkeurig en uitvoerbaar is. Een onvolledig of tegenstrijdig document kan in de praktijk juist onzekerheid creëren. Daarom is bewust tijd besteed aan kwaliteitsborging.
De review zag onder meer op de volledigheid van de risico-mitigatie. Beoordeeld is of de in de inspectie vastgestelde kernrisico's daadwerkelijk werden afgedekt door de voorgestelde maatregelen. Daarnaast is gekeken naar de onderlinge samenhang tussen de documenten. Een back-upbeleid heeft bijvoorbeeld alleen waarde wanneer ook is vastgelegd wie controleert, wanneer er getest wordt en hoe afwijkingen worden opgevolgd. Evenzo heeft een MFA protocol alleen effect wanneer de processen rond autorisatie en periodieke review voldoende duidelijk zijn uitgewerkt.
Een tweede reviewaspect was toepasbaarheid voor de klant. Daarbij is beoordeeld of de formulering en diepgang van de stukken aansloten op een mkb-organisatie en of de adviezen niet zo abstract waren dat ze in de praktijk onbruikbaar zouden zijn. Dit is juist in subsidietrajecten relevant, omdat de regeling gericht is op maatregelen die de cyberweerbaarheid daadwerkelijk vergroten. De review functioneerde daarom als een controlemechanisme op uitvoerbaarheid.
MFA/veilige toegang inclusief retentie en rotatiebeleid
from dataclasses import dataclass, field
from typing import List
@dataclass
class MfaPolicy:
required: bool = True
methods: List[str] = field(default_factory=lambda: ["totp", "fido2"])
grace_period_days: int = 0
allow_remember_device: bool = False
@dataclass
class AccessPolicy:
ip_whitelist: List[str] = field(default_factory=list)
require_mfa_from_new_device: bool = True
session_timeout_minutes: int = 480
max_failed_attempts: int = 5
{
"backup_policy": {
"scope": [
"ordermanagement",
"administratieve data",
"bestandsopslag",
"mailgerelateerde bedrijfsinformatie"
],
"schedule": {
"incremental": "daily 22:00",
"full": "sunday 01:00"
},
"retention": {
"daily": 14,
"weekly": 8,
"monthly": 12
},
"storage": {
"primary_backup_location": "encrypted_offsite_storage",
"secondary_copy": "immutable_archive",
"encryption": "AES-256"
},
"restore_testing": {
"frequency": "quarterly",
"test_type": [
"single file restore",
"full dataset restore"
]
}
}
}
// Geautomatiseerde backupcontrole
#!/bin/bash
BACKUP_DIR="/secure-backups"
LOG_FILE="/var/log/backup-health.log"
TODAY=$(date +%F)
if [ ! -d "$BACKUP_DIR/$TODAY" ]; then
echo "$TODAY ERROR: backup map ontbreekt" >> "$LOG_FILE"
exit 1
fi
FILE_COUNT=$(find "$BACKUP_DIR/$TODAY" -type f | wc -l)
if [ "$FILE_COUNT" -lt 5 ]; then
echo "$TODAY ERROR: backup lijkt onvolledig ($FILE_COUNT bestanden)" >> "$LOG_FILE"
exit 1
fi
echo "$TODAY OK: backup aanwezig en basiscontrole geslaagd" >> "$LOG_FILE"
exit 0