Wprowadzenie do fingerprintingu Canvas i WebGL
Canvas fingerprinting i WebGL fingerprinting to obecnie jedne z najpotężniejszych metod identyfikacji przeglądarek. W 2026 roku ponad 30% topowych stron według badań Electronic Frontier Foundation wykorzystuje fingerprinting canvas do śledzenia użytkowników, a antyboty klasy enterprise (Cloudflare, Akamai, DataDome) traktują te sygnały jako kluczowy wektor reputacji. Dla inżynierów automatyzacji i badaczy bezpieczeństwa zrozumienie, jak te fingerprinty są generowane i jak prezentować spójny profil urządzenia, jest warunkiem koniecznym utrzymania legalnego ruchu.
Problem polega na tym, że fingerprinting nie opiera się na pojedynczym sygnale. To zbiór tysięcy mikrosygnałów — od kolejności szyfrów TLS (JA3/JA4), przez canvas, WebGL, czcionki, aż po behavioral analytics — które razem tworzą unikalny identyfikator. Według FingerprintJS, entropia samego canvas i WebGL potrafi przekroczyć 20 bitów, co oznacza że kombinacja tych dwóch wektorów może wyróżnić 1 przeglądarkę na milion.
W tym artykule rozkładamy mechanizm fingerprintingu na czynniki pierwsze — od pixel-perfect renderowania tekstu na offscreen canvas, przez UNMASKED_RENDERER WebGL, aż po strategie obrony, które nie wywołają flagi ML.
Jak działa canvas fingerprinting
Canvas fingerprinting wykorzystuje fakt, że renderowanie tekstu i kształtów na elemencie <canvas> zależy od kombinacji GPU, sterownika graficznego, systemu operacyjnego i zainstalowanych czcionek. Nawet jeśli dwie maszyny mają ten sam model karty graficznej, różnice w sterownikach, antyaliasingu i hintingu czcionek powodują mikroskopijne różnice w pikselach.
Typowy skrypt fingerprintingowy wykonuje następujące kroki:
- Tworzy offscreen canvas o zdefiniowanych wymiarach (często 240×60 px).
- Rysuje ciąg znaków z określoną czcionką (np.
"Arial 16px"), gradientem i geometrią. - Wywołuje
canvas.toDataURL()lubctx.getImageData(), aby odczytać piksele. - Haszuje wynik (zwykle SHA-256 lub CRC32), tworząc stabilny identyfikator.
Przykład minimalnego skryptu fingerprintingowego:
function canvasFingerprint() {
const canvas = document.createElement('canvas');
canvas.width = 240;
canvas.height = 60;
const ctx = canvas.getContext('2d');
ctx.textBaseline = "top";
ctx.font = "16px 'Arial'";
ctx.fillStyle = "#f60";
ctx.fillRect(125, 1, 62, 20);
ctx.fillStyle = "#069";
ctx.fillText("ProxyHat fingerprint test 🔒", 2, 15);
ctx.fillStyle = "rgba(102, 204, 0, 0.7)";
ctx.fillText("ProxyHat fingerprint test 🔒", 4, 17);
return canvas.toDataURL();
}
const fp = canvasFingerprint();
// Hashuj fp, aby uzyskać stabilny identyfikator
Wynikowy hash jest niezmienny dla tej samej kombinacji GPU+sterownik+OS, ale różni się między urządzeniami. To właśnie ta stabilność sprawia, że canvas fingerprinting jest tak skuteczny — i tak niebezpieczny, gdy próbujesz go naiwnie oszukać.
WebGL fingerprinting — wektor na poziomie GPU
WebGL dodaje kolejną warstwę identyfikacji, opartą bezpośrednio na sprzęcie graficznym. Głównym wektorem są dwa ciągi znaków dostępne przez WEBGL_debug_renderer_info:
- UNMASKED_VENDOR_WEBGL — np.
"Google Inc. (NVIDIA)" - UNMASKED_RENDERER_WEBGL — np.
"ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
Te ciągi ujawniają dokładny model GPU. Dla webgl renderer fingerprint to sygnał o entropii ~15 bitów samodzielnie — karta RTX 4070 jest znacznie rzadsza niż zintegrowana Intel UHD 620, co dodatkowo zawęża pulę.
Dodatkowe wektory WebGL:
- Precision shader —
getShaderPrecisionFormatzwraca wartościrangeMin,rangeMax,precision, które różnią się między vendorami. - Floating-point quirks — renderowanie identycznej sceny WebGL daje różnice na poziomie 1 ULP między kartami AMD i NVIDIA.
- Maksymalne wymiary tekstur —
MAX_TEXTURE_SIZE,MAX_VIEWPORT_DIMS. - Obsługiwane rozszerzenia — lista
gl.getSupportedExtensions()zależy od sterownika.
Przykład odczytu WebGL renderer info:
const gl = document.createElement('canvas').getContext('webgl');
const ext = gl.getExtension('WEBGL_debug_renderer_info');
const vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);
const renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
console.log("Vendor:", vendor);
console.log("Renderer:", renderer);
// Vendor: Google Inc. (NVIDIA)
// Renderer: ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 ...)
Hash WebGL sceny
Zaawansowane antyboty idą dalej: renderują złożoną scenę WebGL (często z tessellation i shaderami obliczeniowymi), odczytują piksele z gl.readPixels() i haszują wynik. To generuje fingerprint sprzętowy, który jest praktycznie niemożliwy do sfałszowania bez modyfikacji sterownika na poziomie jądra.
Dlaczego naiwny szum zawodzi — pułapka randomizacji
Najczęstszym błędem jest wstrzykiwanie losowego szumu do canvas hash przy każdym odświeżeniu strony. Podejście to, popularne w tanich „stealth browserach”, polega na modyfikacji kilku pikseli w getImageData przed zwróceniem wyniku.
W 2026 roku to podejście jest aktywnie flagowane przez detektory ML. Oto dlaczego:
- Niespójność między wywołaniami — legalna przeglądarka zwraca identyczny hash canvas przy każdym wywołaniu w tej samej sesji. Losowy szum generuje różne hashe, co jest sygnałem „bot” o wadze większej niż sam fingerprint.
- Niespójność wewnętrzna — szum w canvas nie koreluje z WebGL renderer. Jeśli canvas mówi „NVIDIA RTX 4070”, ale WebGL zwraca „Apple M2”, detektor widzi sprzeczność.
- Korelacja z innymi sygnałami — canvas hash musi pasować do czcionek, UA-CH, nagłówków Client Hints i TLS fingerprint. Losowość w jednym wektorze psuje całość.
- Renderowanie wielokrotne — nowoczesne antyboty renderują scenę 3–5 razy i porównują hashe. Stabilny, seeded hash przechodzi; losowy nie.
Reguła na 2026: stabilność bierze przewagę nad unikalnością. Lepiej zwracać spójny, seeded fingerprint, który pasuje do deklarowanego GPU, niż próbować być „unikalnym” przy każdym ładowaniu.
Dlaczego proxy rezydencyjne mają znaczenie
Nawet perfekcyjny profil urządzenia — z poprawnym canvas, WebGL, czcionkami i TLS — nie przejdzie, jeśli reputacja IP jest zła. Antyboty łączą fingerprint urządzenia z reputacją sieci w czasie rzeczywistym.
Typowy scenariusz odrzucenia:
- Canvas hash wskazuje na „Chrome 121 na Windows 11 z RTX 4070”.
- IP to datacenter AWS w us-east-1.
- Detektor: „Karta RTX 4070 w datacenter? Nieprawdopodobne.” → flaga.
Proxy rezydencyjne rozwiązują ten problem, ponieważ pochodzą z ISP (np. Comcast, Deutsche Telekom, Orange), a nie z chmury. Połączenie rezydencyjnego IP z spójnym profilem urządzenia tworzy wiarygodną historię: „Użytkownik domowy w Nowym Jorku z kartą NVIDIA”.
ProxyHat oferuje sieć rezydencyjną z geo-targetowaniem na poziomie miasta. Sprawdź dostępne lokalizacje proxy i cennik ProxyHat.
Praktyczna implementacja: ProxyHat + stealth browser
Poniżej znajduje się kompletny, legalny setup dla autoryzowanego testowania lub QA. Połączenie ProxyHat residential exits z przeglądarką stealth, która zwraca seeded, spójne wartości canvas/WebGL.
Krok 1: Konfiguracja ProxyHat
Użyj bramki ProxyHat z geo-targetowaniem na miasto, aby IP pasowało do deklarowanej lokalizacji urządzenia:
# HTTP proxy — Nowy Jork, USA
export HTTP_PROXY="http://user-country-US-city-newyork:PASSWORD@gate.proxyhat.com:8080"
# SOCKS5 proxy — Berlin, Niemcy
export SOCKS5_PROXY="socks5://user-country-DE-city-berlin:PASSWORD@gate.proxyhat.com:1080"
# Test połączenia
curl -x http://user-country-US-city-newyork:PASSWORD@gate.proxyhat.com:8080 \
https://api.ipify.org?format=json
Krok 2: Seeded canvas fingerprint w Playwright
Użyj Playwright z proxy ProxyHat i wstrzyknij stabilny canvas fingerprint, który koreluje z deklarowanym GPU:
from playwright.sync_api import sync_playwright
import hashlib
PROXY = {
"server": "http://gate.proxyhat.com:8080",
"username": "user-country-US-city-newyork",
"password": "PASSWORD"
}
# Seeded canvas hash — stabilny dla sesji
SEED = "rtx4070-win11-chrome121"
CANVAS_HASH = hashlib.sha256(SEED.encode()).hexdigest()
STEALTH_JS = f"""
(() => {{
const origToDataURL = HTMLCanvasElement.prototype.toDataURL;
const origGetImageData = CanvasRenderingContext2D.prototype.getImageData;
const seedHash = "{CANVAS_HASH}";
HTMLCanvasElement.prototype.toDataURL = function(...args) {{
if (this.width > 16 && this.height > 16) {{
// Zwróć seeded, spójny hash zamiast losowego
return "data:image/png;base64," + btoa(seedHash);
}}
return origToDataURL.apply(this, args);
}};
CanvasRenderingContext2D.prototype.getImageData = function(...args) {{
const data = origGetImageData.apply(this, args);
// Modyfikuj tylko piksele w deterministyczny, seeded sposób
for (let i = 0; i < data.data.length; i += 4) {{
data.data[i] = data.data[i] ^ (parseInt(seedHash[i % 64], 16) & 1);
}}
return data;
}};
}})();
"""
with sync_playwright() as p:
browser = p.chromium.launch(
proxy=PROXY,
headless=False,
args=["--disable-blink-features=AutomationControlled"]
)
context = browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/121.0.0.0 Safari/537.36",
viewport={{"width": 1920, "height": 1080}},
locale="en-US",
timezone_id="America/New_York"
)
context.add_init_script(STEALTH_JS)
page = context.new_page()
page.goto("https://browserleaks.com/canvas")
page.screenshot(path="canvas_test.png")
browser.close()
Krok 3: Spójny WebGL renderer
WebGL renderer musi pasować do canvas i deklarowanego UA. Jeśli UA mówi Windows 11, WebGL powinien zwracać kartę NVIDIA lub AMD, a nie Apple M2:
const WEBGL_STEALTH = `
(() => {
const getParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function(param) {
// UNMASKED_VENDOR_WEBGL
if (param === 37445) return "Google Inc. (NVIDIA)";
// UNMASKED_RENDERER_WEBGL
if (param === 37446) return "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)";
return getParameter.call(this, param);
};
})();
`;
context.add_init_script(WEBGL_STEALTH);
Kluczowe zasady spójności:
| Sygnał | Wartość | Musi pasować do |
|---|---|---|
| UA-CH platform | Windows | WebGL vendor (NVIDIA/AMD, nie Apple) |
| Canvas hash | Seeded, stabilny | WebGL renderer (ten sam GPU) |
| IP geolokacja | US/New York | Timezone, locale, nagłówki Accept-Language |
| TLS JA3/JA4 | Chrome 121 fingerprint | UA-CH (ten sam browser) |
Canvas fingerprint spoofing — strategie i pułapki
Canvas fingerprint spoofing to modyfikacja wyniku canvas, aby nie zwracał unikalnego hash. Istnieją trzy podejścia, z różną skutecznością:
- Blokada canvas API —
toDataURLzwraca pusty string. Skuteczność: niska. Antyboty traktują brak canvas jako silny sygnał bot. - Losowy szum — modyfikacja pikseli losowo. Skuteczność: bardzo niska w 2026. ML detektory flagują niespójność.
- Seeded, spójna modyfikacja — deterministyczna zmiana oparta na seedzie sesji. Skuteczność: wysoka, jeśli koreluje z WebGL i UA.
Najlepszą strategią jest seed per profil: każdy profil urządzenia ma swój seed, który determinuje canvas hash, WebGL renderer i czcionki. Profil jest stabilny w obrębie sesji i między sesjami tego samego „urządzenia”.
WebGL renderer fingerprint — co ujawnia i jak ukryć
WebGL renderer fingerprint ujawnia nie tylko model GPU, ale też backend (Direct3D11, Metal, OpenGL). To oznacza, że "ANGLE (NVIDIA, ... Direct3D11 ...)" zdradza Windows, a "ANGLE (Apple, ... Metal ...)" zdradza macOS.
Typowe kombinacje, które detektory uznają za wiarygodne:
| Platforma | WebGL Vendor | WebGL Renderer (przykład) |
|---|---|---|
| Windows 11 + NVIDIA | Google Inc. (NVIDIA) | ANGLE (NVIDIA, RTX 4070, D3D11) |
| Windows 11 + AMD | Google Inc. (AMD) | ANGLE (AMD, RX 7800 XT, D3D11) |
| macOS (M2) | Google Inc. (Apple) | ANGLE (Apple, ANGLE Metal Renderer, Metal) |
| Linux + Mesa | Mesa | Mesa Intel(R) UHD 620 (KBL GT2) |
Błąd polegający na ustawieniu "Apple M2" na profilu Windows to natychmiastowa flaga. Spójność między WebGL a UA-CH jest krytyczna.
Częste błędy i przypadki brzegowe
1. Nieaktualny WebGL renderer
Ustawienie "NVIDIA GeForce GTX 1060" w 2026 roku budzi podejrzenia — to karta z 2016 roku. Detektor może sprawdzić, czy deklarowany GPU jest realistyczny dla bieżącego rynku. Używaj aktualnych modeli: RTX 4070, RTX 4060, RX 7800 XT.
2. Brak korelacji timezone–IP
Jeśli ProxyHat IP jest w Nowym Jorku, ale timezone przeglądarki to Europe/Berlin, detektor widzi sprzeczność. Zawsze ustawiaj timezone zgodnie z IP:
context = browser.new_context(
timezone_id="America/New_York", # pasuje do IP w Nowym Jorku
locale="en-US"
)
3. Headless detection
Headless Chrome w 2026 nadal jest wykrywany przez navigator.webdriver, brak GPU i canvas rendering. Używaj headless=False z Xvfb na Linux lub Playwright w trybie headful.
4. Ignorowanie behavioral analytics
Nawet z perfekcyjnym fingerprintem, brak ruchu myszy, scrollowania i opóźnień między akcjami jest flagowany. Dodaj realistyczne opóźnienia:
import random
page.wait_for_timeout(random.randint(500, 2000)) # 500–2000ms
ProxyHat — konfiguracja i najlepsze praktyki
ProxyHat dostarcza sieć rezydencyjną, mobilną i datacenter. Dla fingerprinting-aware automatyzacji rekomendujemy wyłącznie rezydencyjne proxy, ponieważ:
- IP pochodzi od ISP, nie z chmury.
- Geo-targetowanie na kraj i miasto pozwala dopasować timezone i locale.
- Sticky sessions utrzymują ten sam IP przez całą sesję, co jest krytyczne dla spójności fingerprintu.
Konfiguracja sticky session:
# Sticky session — ten sam IP przez całą sesję
http://user-session-qa12345-country-US-city-newyork:PASSWORD@gate.proxyhat.com:8080
Dokumentacja API ProxyHat: docs.proxyhat.com. Zobacz też nasze przypadki użycia: web scraping i SERP tracking.
Kluczowe wnioski
- Canvas i WebGL fingerprinting to sygnały o wysokiej entropii, obecne na 30%+ topowych stron.
- Naiwny losowy szum jest w 2026 aktywnie flagowany — detektory ML preferują stabilność nad unikalność.
- Spójność między canvas, WebGL, UA-CH, timezone i IP jest ważniejsza niż pojedynczy „idealny” sygnał.
- Proxy rezydencyjne są niezbędne — reputacja IP musi pasować do historii urządzenia.
- Seeded fingerprint per profil to najskuteczniejsza strategia dla legalnej automatyzacji.
Aspekty prawne i etyczne
Fingerprinting spoofing w kontekście legalnej automatyzacji — autoryzowane QA, security research, penetration testing z zgodą właściciela — jest dopuszczalny. Jednak:
- GDPR — fingerprinting jest daną osobową w UE. Zbieranie fingerprintów bez zgody narusza art. 5 i 6 RODO. Zobacz wytyczne Europejskiej Rady Ochrony Danych.
- CFAA — w USA omijanie mechanizmów autoryzacyjnych może naruszać Computer Fraud and Abuse Act, zwłaszcza jeśli celem jest oszustwo.
- robots.txt i ToS — zawsze sprawdzaj warunki serwisu. Scraping wbrew ToS może być podstawą roszczeń cywilnych.
ProxyHat nie wspiera ani nie toleruje użycia proxy do oszustw, fraudu, nieautoryzowanego śledzenia ani omijania mechanizmów bezpieczeństwa w celach nielegalnych. Wszystkie przykłady w tym artykule są przeznaczone do autoryzowanego testowania i badań.






