Canvas-fingerprinting bortom grunderna: varför två identiska Chrome renderar olika pixlar
Två enheter med samma Chrome, OS och GPU renderar ändå olika canvas-pixlar. Varför renderingspipelinen är icke-deterministisk, varför brusinjektion slår tillbaka och var canvas passar in i en modern detektionsstack.
Canvas-fingerprinting har använts i produktion sedan 2012. Idén är enkel: be webbläsaren rendera 2D-innehåll, läs tillbaka pixlarna och hasha dem. Olika enheter producerar något olika pixlar för samma instruktioner, och dessa skillnader är stabila nog för att identifiera en enhet mellan sessioner.
Så mycket är välkänt. Vad som är mindre förstått är varför tekniken fungerar — varför identiska mjukvarukonfigurationer på identisk hårdvara ändå producerar olika pixelutdata. Svaret finns i skärningspunkten mellan GPU-drivrutiner, font-rendering och flyttalsaritmetik.
Renderingspipelinen är inte deterministisk
När JavaScript anropar context.fillText("Cwm fjord bank glyphs vext quiz", 4, 45) renderar Chrome inte pixlarna självt. Det genererar instruktioner för Skia — 2D-grafikbiblioteket — som i sin tur skickar rit-kommandon till en GPU-accelererad backend (vanligtvis ANGLE på Windows, Metal på macOS eller mjukvarufallback i containrar).
Vid varje steg ackumuleras små implementationsskillnader:
-
Skias font-delsystem väljer en font-familj. Om Arial inte är installerad görs en fallback — och den fallbacken varierar beroende på systemets installerade fonter.
-
Den valda fonten renderas i den begärda storleken med FreeType (på Linux), DirectWrite (på Windows) eller Core Text (på macOS). Varje bibliotek har olika hinting-algoritmer.
-
Subpixel-positionering tillämpas. Det är här identiska fonter börjar producera olika pixlar — algoritmen avrundar positioner till fraktionella pixeloffsets, och avrundningsreglerna skiljer sig mellan plattformar.
-
Den rasteriserade texten komponeras på canvasen. Blandning görs med GPU-shaders på hårdvaruaccelererade system, och med CPU-kod i fallback-läge.
Vart och ett av dessa steg kan introducera skillnader på ett eller två pixelvärden. Individuellt osynliga. Kollektivt unika.
GPU-drivrutinsversioner dominerar fingeravtrycket
Två Windows 11-maskiner med Intel UHD Graphics 620-chip kan producera olika canvas-utdata om deras GPU-drivrutiner skiljer sig. Intel släpper drivrutinsuppdateringar flera gånger per år, och varje uppdatering kan ändra subpixel-filtrering, gammakorrigering och text-antialiasing.
Detta innebär att stabiliteten hos ett canvas-fingeravtryck begränsas av hur ofta drivrutiner uppdateras. En användare som uppgraderar sin grafikdrivrutin — ofta tyst, via Windows Update — kommer att se sitt canvas-fingeravtryck förändras.
Detektionssystem hanterar detta genom att behandla canvas-fingeravtrycket som en av många signaler, inte en fristående identifierare. När det förändras men andra signaler förblir stabila (TLS-fingeravtryck, WebGL-renderare, tidszon, installerade fonter) känns besökaren fortfarande igen.
Emoji-rendering är en guldgruva
Det mest identifierande elementet i ett canvas-fingeravtryck är ofta inte text eller former utan emoji. Emoji-rendering beror på emoji-fonten som levereras med operativsystemet — Segoe UI Emoji på Windows, Apple Color Emoji på macOS, Noto Color Emoji på Android.
Även inom ett och samma OS förändras emoji-rendering mellan versioner. Windows 10:s rendering av en regnbågsemoji skiljer sig från Windows 11:s. iOS 16:s leende ansikte har annan antialiasing än iOS 17:s.
Moderna skript för canvas-fingerprinting renderar specifikt sekvenser av emoji, inklusive nya tillägg till Unicode. En besökare som påstår sig köra iPhone Safari men inte kan rendera en emoji som lades till i iOS 17 kör en äldre iOS — eller ljuger om plattformen.
Automationsramverk producerar särskiljande fingeravtryck
Headless Chrome, som körs i en Docker-container utan GPU, använder SwiftShader för rendering. SwiftShader producerar canvas-utdata som är internt konsekvent men skiljer sig från vilken hårdvaruaccelererad Chrome som helst.
Signaturen är igenkännbar: ovanligt ren antialiasing, specifika färgvärden i gradientområden och textkanter som inte matchar någon känd GPU-drivrutin. Ett canvas-fingeravtryck som matchar SwiftShader i Chrome 124 i en Linux-container är nästan säkert automation — ingen riktig användare kör en webbläsare på det sättet.
Puppeteer-extra-stealth försöker förfalska canvas-utdata genom att avlyssna toDataURL() och returnera modifierad data. Men modifieringen introducerar ofta sina egna artefakter — brusmönster som upprepas mellan sessioner, vilket paradoxalt nog gör anti-fingerprinting-insatsen mer detekterbar än att inte göra något alls.
Varför brusinjektion inte fungerar särskilt bra
Integritetsfokuserade webbläsare som Brave injicerar brus i canvas-utdata för att förhindra spårning. Idén är att lägga till små slumpmässiga variationer i pixelvärden så att samma enhet producerar olika fingeravtryck varje session.
I praktiken har brusinjektion tre problem:
1. Bruset i sig är ett fingeravtryck. En besökare vars canvas-utdata förändras vid varje laddning, men vars övriga signaler förblir identiska, är igenkännbar som en brusinjicerande webbläsare. Det i sig är identifierande.
2. Brusalgoritmen är stabil. Braves implementation producerar specifika brusmönster som inte matchar den naturliga variansen i GPU-rendering. Detektionssystem kan skilja canvas-utdata som ser brusinjicerad ut från sådan som ser naturlig ut.
3. Sofistikerade system kombinerar prover. Flera renderingar på samma sida, eller mellan sessioner, kan medelvärdesberäknas. Om bruset är litet konvergerar genomsnittet mot det underliggande deterministiska fingeravtrycket.
Vad canvas-fingerprinting fångar
Utöver den uppenbara visuella utdatan kan canvas-fingerprinting extrahera flera enhetsattribut som sidoeffekter:
Renderingstid — hur lång tid canvasen tar att rendera avslöjar GPU-kapacitet. En 4K-stationär dator med en dedikerad GPU renderar snabbare än en medelklassbärbar dator.
Textmetrik — measureText() returnerar exakta pixelbredder som varierar beroende på font-rendering. Textbredd kan användas som ett fingeravtryck även utan rendering.
Stöd för composite-operationer — vissa webbläsare eller GPU-konfigurationer stöder utökade composite-lägen. Att testa för stöd avslöjar kapacitetsgränser.
Filtereffekter — CSS-liknande filter som tillämpas på canvas producerar olika utdata mellan GPU:er, särskilt blur- och drop-shadow-filter.
Var canvas-fingerprinting passar in i en detektionsstack
Ensamt är canvas-fingerprinting inte en robust identifierare. Drivrutiner förändras. Användare byter webbläsare. Brusinjektion är vanligt bland integritetsfokuserade målgrupper.
Dess verkliga styrka är som en korskontroll. När en session påstår sig vara en återkommande användare baserat på cookies eller kontoinloggning fungerar canvas-fingeravtrycket som en andra signal — matchning mot det historiska fingeravtrycket bekräftar påståendet, medan avvikelse flaggar för account takeover eller session hijacking.
För bot-detektion utmärker sig canvas-fingerprinting när det gäller att fånga containeriserad automation. Riktiga användare har riktiga GPU:er. Riktiga GPU:er producerar igenkännbara renderingssignaturer. Allt som renderar som SwiftShader, eller som en illa förfalskad canvas, hamnar i facket nästan säkert bot.
2012 års teknik fungerar fortfarande 2026 av samma skäl: rendering är deterministisk per miljö men nästan omöjlig att förfalska fullständigt. Varje försök att gömma sig lämnar spår av försöket självt.