en mislukte meting is geen schone app
Mislukt een meting, dan betekent dat niet dat er niets gebeurt, alleen dat ik niets zag. Afwezigheid van bewijs presenteren als bewijs van afwezigheid is de gevaarlijkste fout in dit werk. Een lege uitkomst is 'onbekend', geen vrijspraak.
Onbekend is geen vrijspraak¶
Als een meting mislukt, betekent dat niet dat er niets gebeurt. Het betekent dat ik niets zag. Dat verschil is de kern van dit hele stuk. Afwezigheid van bewijs presenteren als bewijs van afwezigheid is de gevaarlijkste fout in dit werk, omdat de fout eruitziet als een geruststellende conclusie. Iemand leest "0 trackers gevonden" en denkt dat de app schoon is. In werkelijkheid kan de meting kapot zijn gegaan, kan het verkeer versleuteld zijn langsgekomen zonder dat ik erin kon kijken, of kan de tracker gewacht hebben op een handeling die ik nooit deed. Zie Niet alles vuurt bij opstart, sommige trackers wachten op jou.
Een lege uitkomst is daarom "onbekend". Het is een open vraag die om een betere meting vraagt. Wie er een vrijspraak van maakt, geeft een oordeel dat de gegevens niet dragen.
Wanneer een meting eigenlijk mislukt¶
Een meting kan op veel manieren stukgaan zonder dat het meteen opvalt. De opname bevat nul bytes omdat de proxy niet goed tussen het toestel en het netwerk stond. Het verkeer kwam wel binnen maar in een formaat dat ik niet kan lezen, bijvoorbeeld omdat certificaat-pinning de onderschepping blokkeerde. De app detecteerde de meetopstelling en hield zich stil. De sessie stopte na drie seconden terwijl het interessante gedrag pas na het inloggen begint.
In al deze gevallen is de uitkomst dezelfde lege lijst. Het gevaar zit hem er juist in dat een geslaagde schone meting en een mislukte meting op het scherm identiek ogen. Ik kan ze alleen uit elkaar houden door apart vast te leggen of de meting zelf deugde, los van wat ze aantrof.
Certificaat-pinning verdient hier een aparte vermelding, omdat het de meest verraderlijke vorm is. Een app die pint, weigert verbindingen die via mijn onderscheppende proxy lopen. Het gevolg is dat de app zijn eigen backend en zijn trackers gewoon bereikt, terwijl mijn opname leeg blijft. De app werkt, ik zie niets, en zonder controle noteer ik dat als schoon. In werkelijkheid heeft de app zich juist zo gebouwd dat ik niet mag meekijken. Een lege opname bij een app die verder normaal functioneert, is daarom eerder een reden tot argwaan dan tot geruststelling.
Hoe ik een lege meting label¶
Een meting die niets bruikbaars opving, mag niet als "nul trackers, schoon" de boeken in. Ze heet dan "geen bruikbaar verkeer opgevangen". Dat is een uitkomst over mijn meting. Ze zegt op zichzelf niets over de app. Het onderscheid lijkt formeel en het bepaalt de hele conclusie.
Concreet leg ik bij elke meting twee dingen los van elkaar vast:
- Deugde de meting? Kreeg ik verkeer binnen, was het leesbaar, liep de sessie lang genoeg, gedroeg ik me als een echte bezoeker?
- Wat trof de meting aan? Welke hosts, welke trackers, welke identifiers?
Pas als het eerste "ja" is, mag het tweede een uitspraak over de app worden. Is het eerste "nee" of "onzeker", dan blijft de bevinding hangen op "onbekend, meting herhalen". Deze scheiding werk ik door in Label elke bevinding op bewijsniveau.
Ruis van het toestel eraf rekenen¶
Er is nog een kant die de andere richting op fout gaat. Een testtoestel doet uit zichzelf van alles. Het controleert op updates, synchroniseert de tijd, praat met de diensten van het besturingssysteem, haalt pushberichten op. Als ik dat verkeer meetel, reken ik de app aan wat het toestel deed. Dan ontstaat het spiegelbeeld van de valse vrijspraak: een valse beschuldiging.
Daarom trek ik het achtergrondverkeer eraf voordat ik iets aan de app toeschrijf. Ik meet eerst het toestel in rust, zonder de app te openen, en bouw daarmee een lijst van bekende systeemhosts. Die lijst gebruik ik als aftrek bij de echte meting. Een schone uitkomst verdien je pas na die correctie. Ervoor heb je een ruwe lijst die de app dingen aanwrijft die het besturingssysteem deed.
De aftreklijst is zelf een levend ding. Elk toestel en elke Android- of iOS-versie praat met net andere diensten, dus een lijst van vorig jaar dekt de lading niet meer. Ik ververs de rustmeting daarom bij elke nieuwe testopstelling. En ik houd de aftrek conservatief. Bij twijfel of een host van het systeem of van de app komt, laat ik hem staan en markeer ik hem als onzeker. Zo voorkom ik dat ik per ongeluk echt app-verkeer wegpoets onder het mom van ruis. De correctie mag de app niet schoonwassen en mag de app niet zwartmaken. Ze doet precies één ding: het toestel terugbrengen tot wat de app er zelf bovenop legt.
Een HAR controleren op bruikbaarheid¶
Voordat ik een opname interpreteer, laat ik hem eerst een minimale drempel halen. Het onderstaande fragment leest een HAR-bestand, telt de bruikbare requests, trekt bekende systeemhosts eraf, en weigert een conclusie te trekken als er te weinig overblijft.
import json, sys
SYSTEEMHOSTS = {
"connectivitycheck.gstatic.com",
"time.android.com",
"mtalk.google.com",
"push.apple.com",
}
def analyse_har(pad, min_requests=5):
with open(pad, encoding="utf-8") as f:
har = json.load(f)
entries = har.get("log", {}).get("entries", [])
if not entries:
return "ONBEKEND: geen bruikbaar verkeer opgevangen"
app_hosts = {}
for e in entries:
host = e["request"]["url"].split("/")[2].lower()
if host in SYSTEEMHOSTS:
continue # ruis van het toestel, telt niet mee
app_hosts[host] = app_hosts.get(host, 0) + 1
if len(entries) < min_requests:
return f"ONBEKEND: te weinig verkeer ({len(entries)} requests), meting herhalen"
if not app_hosts:
return "ONBEKEND: alleen systeemverkeer gezien, app-verkeer ontbreekt"
return {"unieke_app_hosts": len(app_hosts), "detail": app_hosts}
print(analyse_har(sys.argv[1]))Het punt van deze code is de volgorde van de checks. Een leeg bestand, te weinig verkeer, of alleen systeemhosts leiden allemaal tot "onbekend" en nooit tot "schoon". Alleen een opname die echt app-verkeer bevat, komt door tot een inhoudelijke uitspraak. De ruwe techniek achter het lezen van deze bestanden staat in Netwerkverkeer lezen via HAR-files.
Bewijsniveau: onbekend als volwaardige uitkomst¶
Dit stuk gaat uiteindelijk over bewijsniveau. Ik werk met drie labels: gemeten, afgeleid en vermoed. De fout die ik hier bestrijd, is dat een mislukte meting stilletjes promoveert van "onbekend" naar "gemeten schoon". Die promotie is nergens op gebaseerd en toch gebeurt ze vanzelf, omdat een lege lijst zo geruststellend leest.
In de praktijk geef ik "onbekend" daarom een eigen kolom in mijn overzicht, los van "schoon" en "tracking gevonden". Een app die in die kolom staat, is werk dat nog wacht. Zo kan ik aan het eind van een ronde precies zeggen hoeveel apps ik echt heb doorgemeten en hoeveel er alleen langs de meetlat zijn geweest zonder een bruikbare opname. Dat getal is eerlijk en het beschermt me tegen de neiging om een halve dekking te presenteren als een volledige.
"Onbekend" verdient daarom een eigen plek in het rapport, met dezelfde ernst als een positieve bevinding. Het vertelt de lezer dat hier nog werk ligt. Het beschermt mij tegen de verleiding om een gat in de meting te presenteren als een eigenschap van de app. En het beschermt de app tegen het spiegelbeeld, waarbij ik toestelruis als tracking aanreken. De methode is pas eerlijk als een leegte een leegte mag blijven totdat een betere meting hem vult.
Zie ook Meet zoals een bezoeker, niet zoals een scanner, Een naam in de code is nog geen tracker en Een app kan volledig lokaal, zonder een enkele netwerkcall.
- Eigen onderzoeksdossier: TicketTrigger (Sparta PDT), 2026-07-15dynamische meting mislukt op architectuurfout, dus geen uitspraak over payload