Zo voorkom je onrechtmatige verwerking van persoonsgegevens
Toolonafhankelijk blacklisten en whitelisten
Zit je goed met GDPR? De kans bestaat dat je, ook als je het allemaal goed op orde hebt, onbewust en onrechtmatig persoonsgegevens verwerkt. Er zijn maatregelen die je kunt nemen om dit te voorkomen. Daarbij worden persoonsgegevens overschreven, niet verwijderd – mochten er dus onbedoeld bepaalde gegevens verzameld worden, dan kun je deze goed herkennen en de bron ervan opsporen. We introduceren de ‘PII-preventiematrix’ en laten zien hoe je met behulp van Google Tag Manager persoonsgegevens kunt blacklisten en whitelisten.
Sinds 25 mei 2018 is de Algemene Verordening Gegevensbescherming (kortweg AVG) van toepassing. Binnen de AVG wordt een ruime definitie voor het begrip ‘persoonsgegevens’ gehanteerd, namelijk: ‘alle informatie over een geïdentificeerde of identificeerbare natuurlijke persoon’. Het gaat hierbij dus om gegevens die direct over een persoon gaan, of gegevens die in combinatie met andere gegevens naar deze persoon te herleiden is.
Even wat achtergrond, om mee te beginnen en het geheugen op te frissen: persoonsgegevens mogen alleen verwerkt worden voor het doel waarvoor ze verkregen zijn. Om te voorkomen dat organisaties persoonsgegevens verzamelen zonder dit goed te kunnen verantwoorden, moeten zij de uitgangspunten van privacy by design en privacy by default invoeren. Privacy by design houdt in dat een organisatie er al bij het ontwerpen van producten en diensten voor zorgt dat persoonsgegevens goed worden beschermd. Privacy by default houdt in dat een organisatie technische en organisatorische maatregelen moet nemen om ervoor te zorgen dat zij, als standaard, alléén persoonsgegevens verwerkt die noodzakelijk zijn voor het specifieke doel dat zij wil bereiken. Dit betekent bijvoorbeeld dat het niet toegestaan is om meer gegevens te vragen dan nodig is voor het abonneren op een nieuwsbrief.
“Zonder het zelf te weten kan het toch zo zijn dat je onrechtmatig persoonsgegevens verwerkt”
De kans bestaat echter dat je onrechtmatig persoonsgegevens verwerkt, zonder dat je je hier bewust van bent. Bijvoorbeeld doordat je tools of scripts op je website gebruikt die meten op welke URL een bezoeker zich bevindt. Deze URL kan bijvoorbeeld een e-mailadres bevatten als de klant via een klantmail je website bezoekt.
Er zijn maatregelen die je kunt nemen om het onbedoeld verzamelen en verwerken van persoonsgegevens op je website zoveel mogelijk te voorkomen. Daarbij worden persoonsgegevens overschreven, niet verwijderd – mochten er dus onbedoeld bepaalde gegevens verzameld worden, dan kun je deze goed herkennen en de bron ervan opsporen.
We introduceren de ‘PII-preventiematrix’ en laten zien hoe je met behulp van Google Tag Manager persoonsgegevens kunt blacklisten en whitelisten op een toolonafhankelijke manier – dat wil zeggen: niet voor elk script of elke tool opnieuw, maar slechts één keer voor alle scripts en tools. De uitgewerkte maatregelen zijn bedoeld voor technisch webanalisten, die niet terugdeinzen voor het gebruik van Google Tag Manager en Javascript.
De PII-preventiematrix
De maatregelen die je kunt nemen om de verwerking van persoonsgegevens te voorkomen, deel ik in volgens twee classificaties. Samen vormen ze een matrix die ik de PII-preventiematrix noem: hierin verwijst de afkorting PII naar de Engelse term ‘Personal Identifiable Information’, die min of meer gelijk staat aan het begrip ‘persoonsgegevens’. De classificaties zijn:
1. Toolonafhankelijk versus toolafhankelijk
Bij een toolonafhankelijke oplossing moeten de persoonsgegevens voor elke tool opnieuw vervangen worden. De volgorde waarin verschillende gebeurtenissen plaatsvinden is daarbij als volgt:
- Gegevens zoals een URL komen beschikbaar
- Scripts en/of tools worden geladen
- Elk(e) script en/of tool vervangt de persoonsgegevens
- Elk(e) script en/of tool verwerkt de gegevens die ontdaan zijn van persoonsgegevens
Omdat bij de toolafhankelijke oplossing stap 3 meerdere keren uitgevoerd dient te worden, is dit tamelijk inefficiënt. Daarbij komt dat sommige scripts en/of tools niet eens de mogelijkheid bieden om data zoals URL’s te bewerken alvorens deze door de scripts en/of tools daadwerkelijk te verwerken. De toolonafhankelijke oplossing biedt hiervoor uitkomst. Bij een toolonafhankelijke oplossing is de oplossing tooloverstijgend, en hoeft deze dus slechts een keer toegepast te worden. De volgorde waarin verschillende gebeurtenissen plaatsvinden is daarbij als volgt:
- Gegevens zoals een URL komen beschikbaar
- Eventuele persoonsgegevens binnen de beschikbare gegevens worden vervangen
- Scripts en/of tools worden geladen
- Elk(e) script en/of tool verwerkt de gegevens die ontdaan zijn van persoonsgegevens
2. Blacklisten versus whitelisten
Bij blacklisting definieer je een lijst van gegevens die niet verwerkt mogen worden. Staat een bepaald gegeven niet op de blacklist? Dan mag deze verwerkt worden. Whitelisten werkt andersom: hierbij definieer je een lijst van gegevens die wél verwerkt mogen worden. Een bepaald gegeven mag alleen verwerkt worden als deze op de lijst voorkomt. Daarmee is whitelisten dus strenger dan blacklisten.
De classificaties van hierboven resulteren in een kwadrant van vier oplossingen om de verwerking van persoonsgegevens te voorkomen:
- Toolonafhankelijk blacklisten
- Toolonafhankelijk whitelisten
- Toolafhankelijk blacklisten
- Toolafhankelijk whitelisten
In de rest van deze blog zal ik dieper ingaan op het toolonafhankelijk blacklisten en whitelisten van persoonsgegevens met behulp van Google Tag Manager. In een volgende blog zal ik laten zien hoe je blacklisting en whitelisting op Google Analytics kunt toepassen.
“Het komt regelmatig voor dat metadata persoonsgegevens bevatten”
Aangezien de meeste scripts op een pagina toegang hebben tot de metadata van een webpagina – denk aan de URL en paginatitel – zijn vooral deze gegevens geschikt om op een toolonafhankelijke manier van persoonsgegeven te ontzien. Dat wil zeggen: voordat de gegevens voor andere scripts beschikbaar is. Het komt regelmatig voor dat deze metadata, bedoeld of onbedoeld, persoonsgegevens bevatten. Denk bijvoorbeeld aan een mailadres dat als queryparameter wordt meegestuurd op de bestemmingspagina van een klantmail. Of een postcode die als queryparameter wordt meegestuurd vanaf een vergelijkingssite.
Toolonafhankelijk blacklisten: hoe doe ik dat?
Met de oplossing van toolonafhankelijk blacklisten specificeer je de reguliere expressies waaraan persoonsgegevens voldoen (de blacklist). Vervolgens check je of deze patronen voorkomen in de gegevens die je wilt verwerken. Als dit het geval is, dan vervang je de substrings die aan deze patronen voldoen. Dit doe je voordat de gegevens door andere scripts verwerkt worden (toolonafhankelijk).
Ter illustratie wil ik je graag laten zien hoe je de URL-parameter “foo” en/of “bar” kunt vervangen door “[REDACTED]” en e-mailadressen door “[REDACTED EMAIL]”. De URL “https://www.domein.nl?foo=waarde&bar=waarde&email=siemon@i-spark.nl&foobar=waarde” wordt dan “https://www.domein.nl?foo=[REDACTED]&bar=[REDACTED]&email=[REDACTED_EMAIL]&foobar=waarde”. Dit kun je met behulp van Google Tag Manager realiseren:
a. Definieer je blacklist
- Maak een nieuwe variabele aan van het type ‘Aangepaste JavaScript-macro’ en noem deze “PII”. Zie het voorbeeld hieronder.
- Definieer binnen de nieuwe variabele een array met daarin voor elk type persoonsgegeven een object. In ons voorbeeld gaat het om twee typen persoonsgegevens, namelijk geblackliste parameters en e-mailadressen.
- Geef de objecten die je voor elke type persoonsgegeven gedefinieerd hebt 3 keys: ’name’, ‘regex’ en ‘replacement’. Geef voor de name key een string op waarmee je beschrijft om welk type persoonsgegeven het gaat. Dit is vooral voor jezelf handig. Geef voor de regex key de reguliere expressie op waaraan het type persoonsgegeven voldoet. Geef voor de replacement key de string op waarmee het persoonsgegeven vervangen moet worden.
- Return de gedefinieerde array.
b. Creëer een nieuwe functie die persoonsgegevens vervangt
- Maak een nieuwe variabele aan van het type ‘Aangepaste JavaScript-macro’ en noem deze “return redactData function”. Gebruik hierbinnen de onderstaande Javascript.
- De variabele returnt een functie met twee parameters: de eerste parameter is een gegevensstring, de tweede parameter is de eerder gedefinieerde blacklist die we ‘PII’ hebben genoemd. Voor elk van de gedefinieerde persoonsgegevens in de blacklist checkt de functie of de reguliere expressie voorkomt in de gegevensstring, totdat er een match is. Op dat moment wordt het persoonsgegeven de gegevensstring vervangen door de bijbehorende waarde van de replacement key, en geeft de functie de gegevensstring terug, waarbij persoonsgegevens vervangen zijn.
- Door de functie in een aparte variabele te plaatsen kun je deze altijd aanroepen vanuit iedere tag. Stel, je leest de waardes van formuliervelden uit en wilt deze naar Google Analytics versturen. Om deze gegevens van persoonsgegevens te ontzien voordat je ze naar Google Analytics verstuurt, kun je de zojuist gedefinieerde functie vanuit een tag aanroepen. Daarvoor geef je de gegevensstring en de gedefinieerde blacklist ‘PII’ als argumenten mee. Dat ziet er dan als volgt uit:
{{return redactData function}}(gegevensstring, {{PII}})
c. Creëer een tag die persoonsgegevens vervangt
- Maak een nieuwe tag aan van het type ‘Aangepaste HTML’. Gebruik hierbinnen de onderstaande Javascript.
- De tag a) leest de titel en URL uit van de webpagina waarop de tag geladen wordt, b) vervangt middels bovenstaande functie de eerder gedefinieerde persoonsgegevens in de titel en URL van de webpagina, c) past, indien persoonsgegevens aanwezig zijn, de URL in de browser aan en/of vervangt de titel van de webpagina, en d) verstuurt een event “piiRedacted” naar de dataLayer, tezamen met de nieuwe URL.
d. Creëer een trigger op basis van het “piiRedacted” event
Maak een nieuwe trigger aan van het type ‘Aangepaste Gebeurtenis’ op basis van het “piiRedacted” event. Dit event geeft het moment aan dat alle handelingen in de Custom HTML tag van hierboven uitgevoerd zijn – op dit moment zijn de URL en titel van de webpagina dus ontzien van persoonsgegevens.
e. Vervang de bestaande ‘All Pages’ trigger door de nieuwe “piiRedacted” trigger
Om ervoor te zorgen dat tags van andere scripts pas geladen worden nadat de URL en paginatitel van persoonsgegevens zijn ontzien, moet de ‘All Pages’ trigger op bestaande tags vervangen worden door de nieuwe trigger op basis van het “piiRedacted” event.
Toolafhankelijk whitelisten: hoe doe ik dat?
Met de oplossing van toolonafhankelijk whitelisten definieer je de gegevens die geen persoonsgegevens zijn (de whitelist). Vervolgens buig je deze om tot blacklist-patronen, omdat je juist de waarden wilt vervangen die niet in de whitelist voorkomen. Een voorbeeld zal dit duidelijk te maken.
“Buig je whitelist om naar een blacklist”
Ter illustratie wil ik de waarde van alle URL-parameters vervangen door “[REDACTED]”, behalve die van de parameters “foo” en “bar” – dit is mijn whitelist. Concreet betekent dit dat de URL “https://www.domein.nl?foo=waarde&bar=waarde&email=siemon@i-spark.nl&foobar=waarde” vervangen wordt door “https://www.domein.nl?foo=waarde&bar=waarde&email=[REDACTED]&foobar=[REDACTED]”. Hieronder leg ik stap voor stap uit hoe je dit met behulp van Google Tag Manager kunt realiseren:
a. Definieer je blacklist
- Buig hiervoor je whitelist om naar een blacklist. Het doel is immers om alle parameters te vervangen behalve die van de whitelist. Specificeer dus ‘alle parameters behalve die van de whitelist’ in een reguliere expressie. Op een vergelijkbare manier kun je bijvoorbeeld een patroon specificeren dat matcht met elk woord behalve die van een whitelist.
- Maak een nieuwe variabele aan van het type ‘Aangepaste JavaScript-macro’ en noem deze “PII”.
- Definieer binnen de nieuwe variabele een array met daarin een object met drie keys: ’name’, ‘regex’ en ‘replacement’. Geef voor de name key een string op waarmee je beschrijft om welk type gegeven het gaat als het niet in de whitelist voorkomt. Ik gebruik in dit geval ‘NON-WHITELISTED PARAMETER’. Geef voor de regex key de reguliere expressie op waaraan het type gegeven voldoet dat niet de whitelist voorkomt – in dit geval alle parameters behalve “foo” en “bar”. Geef voor de replacement key de string op waarmee het persoonsgegeven vervangen moet worden. Hierbij verwijst een “$” gevolgd door een cijfer het nummer van de capturing group aan waarvan de match behouden moet blijven in de vervanging.
- Return de gedefinieerde array.
De reguliere expressie is nu ingewikkelder door het gebruik van een negative lookahead. Voor de liefhebber leg ik de reguliere expressie met de negative lookahead graag stukje voor stukje uit:
- ([?&](?!((foo|bar)=))[^=]+=)
Eerste capturing group: match een “?” of “&” die niet gevolgd wordt door “foo=” of “bar=”
- [?&]
Match een ‘?’ of ‘&’.
- (?!regex)
Negative lookahead: match het voorgaande alleen als dit niet gevolgd wordt
door de reguliere expressie.
- ((foo|bar)=)
De string “foo” of “bar” gevolgd door “=”.
“foo|bar” is je whitelist!
- [^=]+=
Match elk karakter behalve “=” minimaal één keer tot “=”
- ([^&$#]+)
Tweede capturing group: match elk karakter behalve “&”, “$” (einde van de string) of “#” minimaal één keer
- De ‘g’ betekent ‘global’. Oftewel, zoek (en vervang) alle matches binnen de string in plaats van alleen de eerste match.
- De ‘i’ geeft aan dat de reguliere expressie niet hoofdlettergevoelig (case-insensitive) is.
Het gebruik van bovenstaande reguliere expressie betekent dat de URL “https://www.domein.nl?foo=waarde&bar=waarde&email=siemon@i-spark.nl&foobar=waarde” twee matches geeft, namelijk “&email=siemon@i-spark.nl” en “&foobar=waarde”. Er komen immers twee parameters voor die niet voldoen aan de whitelist binnen de negative lookahead, en dat zijn “email” en “foobar”. Ik wil alleen de parameterwaarde vervangen door “[REDACTED]” en daarom moet de eerste capturing group van elke match – “&foo=” en “&bar=” – behouden blijven. Dit doe ik door de volledige regex matches te vervangen door “$1[REDACTED]”.
De stappen b t/m e blijven voor het toolonafhankelijk whitelisten gelijk als hierboven beschreven voor het toolonafhankelijk blacklisten.
Wat zijn de takeaways van deze blog?
- De Autoriteit Persoonsgegevens hanteert een brede definitie voor ‘persoonsgegevens’. Dit vraagt om maatregelen om de verwerking van persoonsgegevens zo veel mogelijk te voorkomen. Een combinatie van blacklisting en whitelisting is aan te raden.
- Met de ‘replace’-functie in combinatie met reguliere expressie kun je gemakkelijk persoonsgegevens vervangen. Deze methode kan toolonafhankelijk toegepast worden voordat andere scripts geladen worden en is daarmee zeer efficiënt.
- De toolonafhankelijke oplossing met behulp van reguliere expressie ondersteunt zowel blacklists als whitelists. Voor whitelisting kun je gebruik maken van een negative lookahead.
In een volgende blog komt aan bod hoe je blacklisting en whitelisting op Google Analytics kunt toepassen.