MariaDB en MySQL beveiligen: de stappen na de installatie
Na de pakketinstallatie is een database nog niet veilig. Deze gids loopt mysql_secure_installation door, beantwoordt de unix_socket-vraag en toont een eigen gebruiker per applicatie.
Een vers geïnstalleerde database op een rootserver is zelden zo onveilig als oudere handleidingen beweren, en zelden zo veilig als het pakketsysteem suggereert. Tussen die twee uitersten liggen precies de handelingen die dit artikel beschrijft: wat mysql_secure_installation werkelijk doet, waarom de unix_socket-vraag op moderne systemen anders beantwoord moet worden dan in 2015, hoe een applicatiegebruiker met minimale rechten eruitziet en hoe u wachtwoorden uit de proceslijst houdt.
Alle commando's draaien als root. Werkt u met een gewone gebruiker, zet er dan sudo voor. De uitvoer komt van Debian 13 en Debian 12 en van Ubuntu 24.04 en Ubuntu 22.04.
Uitgangspunt: welk pakket op welke distributie draait
Het eerste struikelblok ligt nog vóór de eerste beveiligingsstap. Debian levert al jaren geen eigen pakket met de naam mysql-server meer. Die naam bestaat daar alleen nog als virtueel pakket zonder eigen versie, uitsluitend zichtbaar via de afhankelijkheden van mariadb-server:
apt-cache policy mysql-server
mysql-server:
Installed: (none)
Candidate: (none)
Version table:
Deze versievergelijking levert dus alleen onder Ubuntu een resultaat op, daar 8.0.46 op zowel 24.04 als 22.04. Op Debian gebruikt u in plaats daarvan apt-cache showpkg mysql-server, dat het virtuele karakter van de naam zichtbaar maakt.
Op Debian is de database daarmee altijd MariaDB. Op Ubuntu zijn beide beschikbaar en moet u kiezen. De versies in de actuele distributies:
| Distributie | mariadb-server | mysql-server |
| Debian 13 | 11.8 | alleen virtuele naam, geen versie |
| Debian 12 | 10.11 | alleen virtuele naam, geen versie |
| Ubuntu 24.04 | 10.11 | 8.0.46 |
| Ubuntu 22.04 | 10.6 | 8.0.46 |
Installeren gaat zoals gebruikelijk:
apt update
apt install -y mariadb-server
Of u werkelijk de verwachte versie te pakken heeft, blijkt niet uit de pakketversie alleen, maar uit de draaiende server:
mariadb -e "SELECT @@version, @@version_comment;"
Het tweede struikelblok is de programmanaam. Vanaf MariaDB 11.0 zitten de MySQL-compatibele namen niet meer in het hoofdpakket, maar in mariadb-client-compat en mariadb-server-compat. Op Debian 13 kan een mysql --version daarom ofwel met een waarschuwing antwoorden, ofwel helemaal niet bestaan:
mysql: Deprecated program name. It will be removed in a future release, use '/usr/bin/mariadb' instead
bash: mysql: command not found
Schrijft u scripts die op alle vier de systemen moeten draaien, gebruik onder MariaDB dan consequent mariadb, mariadb-dump en mariadb-secure-installation. Die namen bestaan sinds MariaDB 10.5, dus ook op Ubuntu 22.04.
mysql_secure_installation stap voor stap
Het gereedschap heet afhankelijk van de server anders. Onder MariaDB is de canonieke naam mariadb-secure-installation, onder MySQL 8.0 blijft het mysql_secure_installation. De oude naam bestaat onder MariaDB op Debian 12 en op Ubuntu 24.04 en 22.04 nog steeds als symlink, op Debian 13 daarentegen niet meer: daar bestaat uitsluitend mariadb-secure-installation.
Een blik op de opties loont, want het programma accepteert onder meer --defaults-file, --socket en --protocol. Dat overzicht staat echter alleen in de handleiding:
man mariadb-secure-installation
Een --help bestaat namelijk niet. Het script verwerkt argumenten helemaal niet, het slikt de onbekende optie stilzwijgend in en start meteen de interactieve procedure. Ontbreekt daarbij een echte console, bijvoorbeeld in een pipeline of in een container zonder terminal, dan herhaalt het de vraag om het wachtwoord eindeloos en keert het nooit uit zichzelf terug. Roep het daarom zonder argument aan, en in een interactieve shell:
mariadb-secure-installation
Op Debian 13 zet het script een duidelijke opmerking vooraf:
NOTE: MariaDB is secure by default in Debian. Running this script is useless at best,
and misleading at worst. This script will be removed in a future MariaDB release in Debian.
Debian vindt de doorloop daar dus overbodig en zal het script in een toekomstige versie verwijderen, na te lezen in /usr/share/doc/mariadb-server/README.Debian.gz. De volgende stappen lonen toch, want ze laten zien wat er gecontroleerd wordt en waarom er op een actueel systeem nauwelijks nog iets te veranderen valt.
De procedure begint met de vraag naar het wachtwoord voor root. De formulering hangt af van de versie van het script:
Enter current password for root (enter for none):
Nieuwere versies vragen in plaats daarvan:
Enter root user password or leave blank:
Beide keren wordt hetzelfde bedoeld. Bij een verse installatie bestaat er geen wachtwoord, druk hier dus gewoon op Enter.
Daarna volgen de eigenlijke beslissingen. Volgorde en formulering verschillen tussen MariaDB en MySQL, inhoudelijk gaat het om dezelfde vijf punten.
De unix_socket-vraag
Bij MariaDB verschijnt vervolgens:
Switch to unix_socket authentication [Y/n]
Die vraag zorgt voor verwarring, omdat hij op alle hier behandelde systemen allang beantwoord is. Sinds MariaDB 10.4 is root@localhost standaard beveiligd via de plug-in unix_socket, en dat geldt voor 10.6 op Ubuntu 22.04 net zo goed als voor 11.8 op Debian 13. Bij MySQL 8.0 heet de tegenhanger auth_socket, en de assistent zegt dat ook openlijk:
Skipping password set for root as authentication with auth_socket is used by default.
In de praktijk betekent dat: wie als systeemgebruiker root is ingelogd, komt met mariadb zonder wachtwoord in de database. Wie dat niet is, komt er helemaal niet in, ook niet met het juiste wachtwoord. Dat is geen tekortkoming, maar de sterkere variant. Er bestaat geen wachtwoord dat via een back-up, een configuratiebestand of een schermafbeelding kan weglekken. Het antwoord op de vraag luidt dus ja, behouden, en een extra rootwachtwoord is op een enkele applicatieserver overbodig.
De werkelijke toestand is alleen in de echte tabel te controleren. De voor de hand liggende query SELECT user, host, plugin FROM mysql.user brengt u hier namelijk op een dwaalspoor: bij root toont die de waarde mysql_native_password, terwijl in werkelijkheid unix_socket geldt. Bij MariaDB vanaf 10.4 is mysql.user nog slechts een view op mysql.global_priv, en die view kent per account maar één authenticatiemethode. Wie daarop vertrouwt, houdt de server ten onrechte voor wachtwoordgeauthenticeerd. De volledige regel staat in het JSON-veld Priv van de echte tabel:
mariadb -e "SELECT User, Host, JSON_DETAILED(Priv) FROM mysql.global_priv;"
Voor root op localhost staat daar onder MariaDB in essentie dit:
{"plugin":"mysql_native_password","authentication_string":"invalid","auth_or":[{},{"plugin":"unix_socket"}]}
De eerste vermelding is de wachtwoordmethode tegen de onbruikbare hash van de tekenreeks invalid, die niemand kan raden. De tweede vermelding onder auth_or is de socketauthenticatie die werkelijk geldt. Compacter vraagt u beide zo op:
mariadb -e "SELECT User, Host, JSON_VALUE(Priv,'$.plugin') AS plugin, JSON_QUERY(Priv,'$.auth_or') AS auth_or FROM mysql.global_priv;"
Verwacht wordt bij root en localhost een unix_socket, zo niet in de kolom plugin, dan onder auth_or. Staat daar uitsluitend een wachtwoordmethode en niets onder auth_or, dan werkt het account puur met een wachtwoord. Onder MySQL 8.0 bestaat mysql.global_priv niet, daar is mysql.user een echte tabel en moet de kolom plugin de waarde auth_socket tonen. Uit de MariaDB-view lezen kan overigens nog steeds, erin schrijven niet meer.
Alleen wanneer een tool dwingend een wachtwoord nodig heeft, bijvoorbeeld een monitoring die niet als root draait, schakelt u om. Zinvoller is het dan echter om een tweede beheeraccount aan te maken in plaats van root een andere rol te geven. In MariaDB vanaf 11.6, dus ook in 11.8 op Debian 13, kunt u een account bovendien aan een bepaalde systeemgebruiker koppelen:
CREATE USER 'dbadmin'@'localhost' IDENTIFIED VIA unix_socket AS 'deploy';
Daarmee mag de systeemgebruiker deploy inloggen als databasegebruiker dbadmin, zonder dat de namen gelijk hoeven te zijn. Op Debian 12 en de Ubuntu-versies wordt de tekenreeks na AS nog genegeerd, daar moeten systeemgebruiker en databasegebruiker dezelfde naam hebben.
De vier resterende vragen
De rest is onomstreden en wordt overal met ja beantwoord: anonieme gebruikers verwijderen, inloggen als root op afstand verbieden, de database test inclusief rechten verwijderen, rechtentabellen opnieuw laden. Op een actuele Debian of Ubuntu zijn anonieme gebruikers en de testdatabase meestal toch al niet aangemaakt, het script meldt dan simpelweg dat er niets te doen was.
Bij MySQL 8.0 komt er een vraag bij die MariaDB niet kent:
Would you like to setup VALIDATE PASSWORD component?
Deze component dwingt minimumeisen af voor alle wachtwoorden die voortaan worden ingesteld. Ze is nuttig wanneer meerdere personen gebruikers aanmaken. Ze is lastig wanneer een provisioningscript willekeurige wachtwoorden genereert die per ongeluk geen speciaal teken bevatten. Dan breekt het script af met:
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
Wie ze inschakelt, moet de wachtwoordgenerator daar vooraf op instellen. Het standaardniveau is MEDIUM en vereist minstens acht tekens, hoofdletters en kleine letters, een cijfer en een speciaal teken.
Als het misgaat: terug in de database
De meest voorkomende manier om uzelf buiten te sluiten, is de goedbedoelde overstap van unix_socket naar een wachtwoord dat vervolgens zoekraakt. Of andersom: een oud script maakt /etc/mysql/debian.cnf opnieuw aan, en ineens klopt er niets meer. De foutmeldingen waarop dan gezocht wordt, luiden:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
ERROR 1524 (HY000): Plugin 'unix_socket' is not loaded
Fout 1698 betekent: het account verwacht unix_socket, maar u bent niet de bijbehorende systeemgebruiker. Een sudo ervoor lost dat vaak al op. Fout 1045 betekent: er wordt een wachtwoord verwacht en het uwe klopt niet.
Komt u er helemaal niet meer in, start de server dan zonder rechtencontrole. Bij MariaDB gaat dat netjes via de omgevingsvariabele die de meegeleverde systemd-unit uitleest, geheel zonder pakketbestanden te bewerken:
systemctl stop mariadb
systemctl set-environment MYSQLD_OPTS="--skip-grant-tables --skip-networking"
systemctl start mariadb
Verbind nu met mariadb -u root en zet de toestand terug. Belangrijk is de FLUSH PRIVILEGES vooraf, want zonder geladen rechtentabellen mislukt ALTER USER:
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket;
Draai dit daarna beslist weer terug, anders start de server na elke reboot onbeschermd:
systemctl stop mariadb
systemctl unset-environment MYSQLD_OPTS
systemctl start mariadb
Bij MySQL 8.0 op Ubuntu werkt deze weg niet, omdat de unit zo'n variabele niet uitleest en omdat ALTER USER onder --skip-grant-tables extra valkuilen kent. Daar gebruikt u een startbestand. Dat moet in een map staan die AppArmor het serverproces toestaat, anders mislukt de start met Can't open file. /var/lib/mysql-files is toegestaan, /tmp niet:
systemctl stop mysql
echo "ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;" > /var/lib/mysql-files/reset.sql
chown mysql:mysql /var/lib/mysql-files/reset.sql
systemctl edit mysql
In de editor komt een overschrijving van het startcommando, de lege eerste regel is nodig om de oorspronkelijke waarde te wissen:
[Service]
ExecStart=
ExecStart=/usr/sbin/mysqld --init-file=/var/lib/mysql-files/reset.sql
Na systemctl daemon-reload en een start is het account gereset. Verwijder daarna de overschrijving met systemctl revert mysql en wis het bestand. Draait u databases op gescheiden systemen, dan vindt u aanvullende aanwijzingen voor het beveiligen van de toegang in het artikel SSH-server beveiligen.
Een eigen gebruiker per applicatie in plaats van root
De meest effectieve stap komt in geen enkele assistent voor. Applicaties mogen niet als root verbinden, en ze hebben ook geen GRANT ALL nodig. Een typische webapplicatie leest en schrijft rijen, ze maakt geen databases aan en ze leest geen bestanden van de server.
CREATE DATABASE shopdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'shopapp'@'localhost' IDENTIFIED BY 'HierEenLangWillekeurigWachtwoord';
GRANT SELECT, INSERT, UPDATE, DELETE ON shopdb.* TO 'shopapp'@'localhost';
Daaraan zijn drie dingen belangrijk. Ten eerste de punt in shopdb.* in plaats van *.*: rechten op *.* zijn globale rechten en gelden ook voor mysql en information_schema. Ten tweede de vermelding @'localhost' in plaats van @'%': daarmee is het account uitsluitend lokaal bruikbaar, zelfs als de poort later een keer openstaat. Ten derde ontbreekt WITH GRANT OPTION, want een account dat rechten kan doorgeven, is feitelijk een beheerder.
Schemawijzigingen lopen dan via een tweede account dat alleen bij het deployment wordt gebruikt:
CREATE USER 'shopmigrate'@'localhost' IDENTIFIED BY 'EenAnderLangWillekeurigWachtwoord';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, INDEX, REFERENCES ON shopdb.* TO 'shopmigrate'@'localhost';
Dat klinkt als extra werk en is precies het punt waarop een SQL-injectie in de applicatie een vervelend datalek wordt in plaats van een totaalverlies. Een account zonder DROP kan geen tabel verwijderen.
Controleren doet u niet aan de formulering van de GRANT, maar aan het resultaat:
SHOW GRANTS FOR 'shopapp'@'localhost';
Verwacht worden precies twee regels: een GRANT USAGE ON *.*, dat enkel het inlogrecht vertegenwoordigt en geen enkele toegang tot gegevens betekent, en de regel met de vier rechten op shopdb.*. Duikt daar ALL PRIVILEGES ON *.* op, dan stond de punt op de verkeerde plek. De tweede, veelzeggendere proef is een keer inloggen met het nieuwe account en een SHOW DATABASES;. Zichtbaar mogen alleen information_schema en shopdb zijn.
Een veelvoorkomende fout bij het aanmaken:
ERROR 1396 (HY000): Operation CREATE USER failed for 'shopapp'@'localhost'
Dat betekent bijna altijd dat het account al bestaat, vaak als restant van een eerdere poging. DROP USER 'shopapp'@'localhost'; en dan opnieuw van voren af aan.
bind-address: waar de database eigenlijk luistert
Op alle vier de distributies luistert de database na de pakketinstallatie alleen op 127.0.0.1. Die regel staat bij MariaDB in /etc/mysql/mariadb.conf.d/50-server.cnf en bij MySQL 8.0 in /etc/mysql/mysql.conf.d/mysqld.cnf. Kijken in plaats van aannemen:
grep -R "bind-address" /etc/mysql/
Bij MySQL 8.0 is er een tweede regel die vaak over het hoofd wordt gezien: mysqlx-bind-address stuurt het X-protocol op poort 33060 aan. Wie alleen bind-address wijzigt, opent onder omstandigheden maar de halve toegang of laat de tweede poort openstaan.
De betrouwbaarste controle is niet het configuratiebestand, maar de kernel:
ss -lntp
LISTEN 0 80 127.0.0.1:3306 0.0.0.0:* users:(("mariadbd",pid=712,fd=22))
Staat daar 0.0.0.0:3306 of *:3306, dan is de dienst via het netwerk bereikbaar. Aanvullend levert de server zijn eigen kijk op de zaak:
mariadb -e "SELECT @@bind_address, @@port, @@skip_networking;"
Twee valkuilen komen hier veel voor. De eerste: de bestanden in mariadb.conf.d worden in alfabetische volgorde gelezen, en de als laatste gelezen instelling wint. Schrijft u uw wijziging in een eigen bestand, noem het dan 99-eigen.cnf en niet 10-eigen.cnf. Precies daarop stranden de meeste meldingen waarin MariaDB bind-address zogenaamd negeert. Het voordeel van een eigen bestand: pakketupdates vragen niet om conflictoplossing, omdat het meegeleverde bestand ongemoeid blijft.
De tweede valkuil: wie de netwerktoegang helemaal niet nodig heeft, gaat een stap verder dan bind-address en zet skip-networking. Dan bestaat er geen TCP-poort meer, alleen nog de Unix-socket. Dat is de juiste instelling voor het standaardgeval van webapplicatie en database op dezelfde server, maar het kost zenuwen wanneer een applicatie 127.0.0.1 in de configuratie heeft staan in plaats van localhost: bij 127.0.0.1 dwingen de clientbibliotheken TCP af.
Toegang van buitenaf alleen wanneer het echt nodig is
Een databasepoort die open op het internet staat, wordt binnen enkele uren gevonden en daarna onafgebroken bestookt met inlogpogingen. Het beste antwoord op de vraag naar externe toegang is daarom om die te vermijden. Voor incidenteel onderhoud volstaat een SSH-tunnel die op uw eigen computer een lokale poort op de databasesocket van de externe server legt. Het databasegereedschap verbindt dan met 127.0.0.1, zonder dat de server iets op het netwerk openzet.
Voor permanente verbindingen tussen meerdere servers is een WireGuard-tunnel de nette oplossing. De database bindt dan uitsluitend aan het tunneladres, niet aan het publieke IP-adres.
Moet het toch een open poort zijn, dan grijpen vier maatregelen in elkaar. De server bindt aan precies één intern adres. De firewall laat alleen het bekende bronadres door. Het databaseaccount is aan datzelfde adres gebonden, dus 'shopapp'@'10.0.0.5' en nooit 'shopapp'@'%'. En de verbinding wordt versleuteld afgedwongen:
ALTER USER 'shopapp'@'10.0.0.5' REQUIRE SSL;
Bij het testen van buitenaf komt u twee fouten tegen die vaak verward worden. De eerste betekent dat niemand antwoordt, dus firewall of bind-address:
ERROR 2003 (HY000): Can't connect to MySQL server on '203.0.113.10:3306' (110)
De tweede betekent dat de server wel antwoordt en de verbinding bewust weigert, er ontbreekt dus een passend account voor deze herkomst:
ERROR 1130 (HY000): Host '203.0.113.55' is not allowed to connect to this MariaDB server
Lokaal is de klassieker weer dat de dienst simpelweg niet draait:
ERROR 2002 (HY000): Can't connect to local server through socket '/run/mysqld/mysqld.sock' (2)
Wachtwoorden niet op de commandoregel
De aanroep mariadb -u shopapp -pGeheim123 werkt en is toch een fout. De server zegt het zelf:
Warning: Using a password on the command line interface can be insecure.
Daar zitten twee redenen achter. Ten eerste belandt de regel in de shell-historie. Ten tweede is de commandoregel van een proces op een standaardsysteem voor elke ingelogde gebruiker zichtbaar via ps. Op een server met meerdere klanten of meerdere diensten is dat een moeiteloze wachtwoorddiefstal.
De juiste weg voor mensen is -p zonder toevoeging. Dan wordt er interactief gevraagd en staat er niets in de historie:
mariadb -u shopapp -p shopdb
De juiste weg voor scripts en cronjobs is een optiebestand met strakke rechten. Aanmaken met de juiste modus in één stap:
install -m 600 /dev/null /root/.my.cnf
Inhoud:
[client]
user=backup
password=HierEenLangWillekeurigWachtwoord
Daarna vindt elke client de inloggegevens zelf. Voor gescheiden taken maakt u meerdere bestanden aan en verwijst u er gericht naar. Daarbij geldt een regel waarop velen stranden: --defaults-extra-file en --defaults-file moeten de eerste optie van de aanroep zijn, anders worden ze zonder commentaar genegeerd.
mariadb-dump --defaults-extra-file=/root/.my-backup.cnf --single-transaction shopdb
De omgevingsvariabele MYSQL_PWD is geen oplossing. Die staat in /proc en is daarmee net zo zichtbaar als de commandoregel. Onder MySQL 8.0 bestaat daarnaast mysql_config_editor, dat een bestand ~/.mylogin.cnf schrijft. De inhoud is versluierd, maar niet versleuteld, en MariaDB kent dat gereedschap niet. In gemengde omgevingen is het eenvoudige optiebestand met modus 600 de betrouwbaardere keuze.
Een laatste punt betreft back-ups. Een dump bevat alles wat de applicatie ziet, en een back-upaccount heeft daarvoor geen schrijfrechten nodig. Voor mariadb-dump met --single-transaction volstaat doorgaans dit:
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES ON shopdb.* TO 'backup'@'localhost';
GRANT PROCESS ON *.* TO 'backup'@'localhost';
Oplevering: waaraan u ziet dat het klopt
Een commando dat zonder fout doorloopt, bewijst niets. Deze zes proeven bewijzen wel iets:
- Het rootaccount gebruikt socketauthenticatie:
mariadb -e "SELECT User, Host, JSON_VALUE(Priv,'$.plugin') AS plugin, JSON_QUERY(Priv,'$.auth_or') AS auth_or FROM mysql.global_priv;"toont bijrooteenunix_socket, ofwel in de kolomplugin, ofwel onderauth_or. De viewmysql.userdeugt daar niet voor, die geeft alleen de eerste methode weer. Onder MySQL 8.0 is omgekeerd de kolomplugininmysql.usermaatgevend, daar moetauth_socketstaan. - Er zijn geen anonieme accounts:
mariadb -e "SELECT user, host FROM mysql.user WHERE user = '';"levert een lege resultaatverzameling op. - De testdatabase is weg:
mariadb -e "SHOW DATABASES LIKE 'test';"levert niets op. - De poort is dicht:
ss -lntptoont voor 3306 ofwel helemaal niets, ofwel uitsluitend127.0.0.1. - Het applicatieaccount is beperkt: inloggen daarmee toont bij
SHOW DATABASES;alleen de eigen database, en eenDROP TABLEmislukt. - Nergens een wachtwoord in platte tekst:
grep -rs "password" /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ /etc/cron.monthly/vindt niets, en evenmincrontab -lvoor root en een blik in/var/spool/cron/crontabs/, en de optiebestanden hebben modus 600. De optie-shoort erbij, omdat een ontbrekende map de aanroep anders met exitcode 2 afbreekt: op Debian 13 bestaat/etc/cron.dna een pure database-installatie niet, daar is nog helemaal geen cron-pakket geïnstalleerd.
Wie deze zes punten op een nieuwe server afwerkt, heeft de overgrote meerderheid van de aanvallen op databases al uitgesloten, zonder ook maar één extra stuk software te installeren. De rest is updatediscipline en een werkende back-up waarvan het terugzetten minstens één keer is geoefend.
Veelgestelde vragen
Heb ik onder MariaDB eigenlijk nog wel een rootwachtwoord nodig?
Waarom zegt mijn Debian dat het pakket mysql-server niet bestaat?
Hoe kom ik weer in de database als ik mezelf heb buitengesloten?
Wat betekent ERROR 1698 tegenover ERROR 1045?
Is bind-address = 127.0.0.1 genoeg om de database te beveiligen?
Waarom mag de applicatie de database niet als root benaderen?
Hoe geef ik een cronjob veilig een databasewachtwoord mee?
2026 KernelHost GmbH. Alle rechten voorbehouden. Deze handleiding is auteursrechtelijk beschermd. Publicatie op andere websites, geheel, gedeeltelijk of in bewerkte vorm, is zonder onze schriftelijke toestemming niet toegestaan. Citeren met bronvermelding en link is uitdrukkelijk welkom.

