en naam in de code is nog geen tracker
Een herkenbare naam in de broncode bewijst niet dat een tracker actief is, en soms niet eens dat het de partij is die je denkt. Alleen de gemeten byte op de lijn bevestigt het. Wie op een tekstmatch afgaat, telt trackers die er niet zijn, en dat is precies wat een tegenpartij eruit pikt.
Een naam is geen meting¶
Een herkenbare naam in de broncode is geen bewijs dat een tracker actief is. Soms is het niet eens bewijs dat het de partij is die je denkt. Een bibliotheek statisch aantreffen laat zien dat de code aanwezig is. Het laat niet zien dat die code draait, laat staan dat ze gegevens verstuurt. Alleen de gemeten byte op de lijn bevestigt dat.
Dat onderscheid lijkt klein en is het niet. Het verschil tussen "aanwezig" en "actief" is het verschil tussen een verdenking en een bevinding. Een verdenking mag mijn zoektocht sturen. In het rapport hoort alleen wat ik heb zien gebeuren.
Wat een statische vondst wel zegt¶
Een naam in de code is een aanwijzing, en een goede. Als ik in een app-bestand een bekende SDK-prefix vind, weet ik waar ik moet kijken. Het is de landkaart die me naar de meting leidt. In mijn werkwijze staat dat aan het begin van de keten, bij het vermoeden, zie Mijn werkwijze: van vermoeden naar bevinding.
Wat een statische vondst niet draagt, is de conclusie. Code kan meegeleverd zijn zonder ooit te worden aangeroepen. Een SDK zit vaak transitief in een app omdat een andere bibliotheek ervan afhankelijk is, zonder dat de ontwikkelaar hem bewust gebruikt. Er zijn dode codepaden, functies achter een schakelaar die uit staat, en modules die pas laden bij een handeling die de gemiddelde bezoeker nooit verricht. Zie Niet alles vuurt bij opstart, sommige trackers wachten op jou: aanwezig zijn en vuren zijn twee verschillende toestanden.
Het voorbeeld¶
Een pakketnaam die begint met een bekend merk hoeft dat merk niet te zijn. Een intern app-framework van een grote techpartij kan de naam van een heel ander product dragen. De naamruimte van een softwarepakket is door de ontwikkelaar gekozen. Er is geen instantie die controleert of com.merk.iets werkelijk bij dat merk hoort of dat het gegevens naar dat merk stuurt.
Wie op de naam afgaat, schrijft verkeer toe aan een partij die er niets mee te maken heeft. Dat is een fout in twee richtingen tegelijk. Je telt een tracker die er niet actief is, en je hangt hem aan de verkeerde eigenaar. Beide zijn los al genoeg om een bevinding onderuit te halen.
Waarom de byte op de lijn beslist¶
De enige harde bevestiging is het waargenomen verkeer. Ik meet het toestel zoals een bezoeker het gebruikt, leg het vast als HAR, en tel wat er werkelijk over de lijn ging. Meten zoals een echte bezoeker is daarbij een voorwaarde, want een kale scanner lokt ander gedrag uit dan een mens; zie Meet zoals een bezoeker, niet zoals een scanner. Het verschil met een tekstmatch is te zien in de commando's:
# Statisch: aanwezigheid. Dit bewijst niet dat er iets vuurt.
grep -r "com.merk.tracker" ./app-uitgepakt/
# Gemeten: wat het toestel echt verstuurde, uit de HAR.
jq -r '.log.entries[].request.url' verkeer.har | sort -uDe eerste regel vindt een string. De tweede toont een lijst adressen die het toestel daadwerkelijk heeft aangeroepen. Alleen de tweede telt mee als bevinding.
Een valkuil binnen die meting is de toeschrijving zelf. De Referer-header lijkt te vertellen welke pagina een verzoek uitlokte, maar die is onbetrouwbaar. Stealth-scripts vervalsen hem, en bij diep doorklikken lekt de context van de ene pagina in de volgende. Betrouwbaarder is de pageref in de HAR, die elk verzoek aan de juiste geladen pagina koppelt. De les is dezelfde als bij de pakketnaam: vertrouw niet op het label dat een partij zelf meestuurt, vertrouw op de structuur van de meting.
De twee soorten fout die dit voorkomt¶
Het onderscheid tussen aanwezig en actief beschermt tegen twee fouten die elkaars spiegelbeeld zijn. De eerste is de vals-positieve: je telt een tracker die er staat maar niet vuurde. De tweede is de vals-attributie: hij vuurde wel, maar je hangt hem aan de verkeerde partij. De pakketnaam die een ander merk draagt, is een geval van de tweede soort. Het verkeer bestaat, alleen de eigenaar die je eraan koppelt, klopt niet.
Beide fouten hebben dezelfde oorzaak: vertrouwen op een label dat door een ander is gekozen. Een pakketnaam is door de ontwikkelaar bedacht. Een Referer wordt door de browser of een script meegestuurd en kan vervalst zijn. Een cookienaam zegt niets over wie de cookie werkelijk uitleest. Telkens is de valkuil dat een naam zichzelf lijkt te verklaren. De meting doet dat niet vanzelf. Ik moet elke stap terugvoeren op een waarneembaar feit: dit verzoek ging naar dit adres, op dit tijdstip, uitgelokt door deze pagina. Rollen die je eraan toekent, moeten uit die feiten volgen, niet uit de naam. Zie Trackers hebben rollen, en die verwar je niet.
Dat is bewerkelijker dan een lijst met namen aftikken, en dat is de prijs. Wie snel wil scoren, telt strings en heeft binnen een minuut een indrukwekkend hoog getal. Dat getal houdt geen stand. Het trage werk levert een lager getal op dat wél overeind blijft in een gesprek met een tegenpartij.
Waarom een tegenpartij hier op wacht¶
Dit is precies de fout waar een advocaat of woordvoerder op wacht. Eén tracker die je op een tekstmatch hebt geteld en die niet bleek te vuren, en je hele lijst wordt verdacht. De tegenpartij hoeft niet je hele analyse te weerleggen. Hij hoeft één regel te vinden die aantoonbaar niet klopt, en hij zet daarmee de betrouwbaarheid van al het andere ter discussie. Zie Een mislukte meting is geen schone app voor de spiegelfout aan de andere kant.
Daarom tel ik alleen wat ik heb zien gebeuren, niet wat ik heb zien staan. Een lijst die volledig uit gemeten verkeer bestaat, geeft een tegenpartij geen enkel houvast. Elke regel verwijst naar een verzoek dat werkelijk is verstuurd, met tijdstip en adres. Dat valt niet weg te praten met de opmerking dat de code misschien niet draaide.
Wat het voor mijn werk betekent¶
Deze regel bepaalt de scheidslijn in al mijn rapporten. Statische vondsten gaan in de kolom vermoed en sturen waar ik dieper kijk. Gemeten verkeer gaat in de kolom gemeten en draagt de conclusie. Ik meng die twee nooit in één getal.
Het effect is dat mijn lijsten korter zijn dan die van een scanner die op namen telt. Ze zijn ook onaantastbaar op het punt dat telt. Wanneer iemand een bevinding aanvecht, kan ik het bijbehorende verzoek uit de HAR laten zien. Daar houdt de discussie op.
Die keuze heeft een prijs die ik bewust betaal. Ik loop het risico dat mijn cijfer lager uitkomt dan de werkelijkheid, en dat iemand mijn rapport daardoor minder alarmerend vindt dan het van een naam-teller zou zijn. Dat neem ik voor lief. Een bevinding die je kunt tonen is meer waard dan een bevinding die indruk maakt. In een gesprek met een woordvoerder, een advocaat of een toezichthouder is het enige dat telt of ik het verzoek kan laten zien dat mijn claim draagt. Alles wat op een naam of een vermoeden steunt, verdampt in dat gesprek. Wat op de gemeten byte steunt, blijft staan.
Deze regel is ook de reden dat ik statische analyse niet weggooi. Ze is de eerste helft van het werk, de helft die me vertelt waar ik moet meten. De fout zou zijn om die eerste helft voor de conclusie aan te zien. Aanwijzing en bewijs zijn twee stations op dezelfde route, en ik verwar het vertrek niet met de aankomst.
Zie ook Een mislukte meting is geen schone app, Label elke bevinding op bewijsniveau en Niet alles vuurt bij opstart, sommige trackers wachten op jou.
- Eigen meetregel bij HAR-analyseeen domeinnaam in een script zegt niets tot er verkeer naartoe gaat