In this Article
WebGL-Fingerprinting ist eine Identifizierungstechnik, die Anti-Bot-Systeme häufig einsetzen, um automatisierte Aktivitäten zu erkennen. Da sie Signale auf Hardwareebene nutzt, ist sie schwer zu handhaben und stellt für alle, die Web Scraping geschäftlich einsetzen, eine weitere Herausforderung dar. Es gibt jedoch Möglichkeiten, unauffällig zu bleiben und Daten zu sammeln. Lesen Sie weiter, um mehr zu erfahren.
Was ist WebGL? Eine ausführliche Erklärung
WebGL steht für Web Graphics Library und ist eine JavaScript API. Browser verwenden sie, um dynamische 2D- und 3D-Grafiken darzustellen, ohne dass Plugins installiert werden müssen. Für diese Rendering-Aufgaben stützt sich die API stark auf die GPU, also die Graphics Processing Unit. Websites nutzen WebGL heute umfassend für visuelle Effekte, Spiele und komplexe grafische Benutzeroberflächen. Tatsächlich setzt sich WebGL 2 zunehmend durch, da es mehr Funktionen bietet. Moderne Browser wie Chrome, Edge und Safari unterstützen WebGL 2 zu 95-99%, während ältere und Headless-Browser weiterhin Defizite aufweisen.
Da es Hunderte von GPUs gibt und selbst Modelle desselben Herstellers sich stark unterscheiden, wird dasselbe Bild unterschiedlich gerendert. Darüber hinaus beeinflussen auch der Browser, installierte Treiber und Hardwarevarianten, etwa die Verbindung zwischen GPU und Mainboard, das Ergebnis. Stellen Sie sich einen Elektronikmarkt vor, in dem mehrere Dutzend Fernseher dieselbe Werbung zeigen, die Bilder aber jeweils leicht anders aussehen. Das bildet eine Grundlage für WebGL-Fingerprinting. Beachten Sie, dass WebGL-Fingerprinting nur stattfindet, wenn JavaScript beteiligt ist. Eine statische HTML-Seite kann es nicht durchführen.
WebGL-Fingerprinting: ein Überblick Schritt für Schritt
Vereinfacht sieht der gesamte Prozess so aus:
- Eine Website erstellt ein <canvas>-Element, das im HTML der Seite verborgen ist. Es initialisiert die WebGL-Rendering-Umgebung.
- JavaScript nutzt Aufrufe von gl.getParameter(), um GPU-Merkmale wie Hersteller und Modell auszulesen.
- Ein Fingerprinting-Skript lässt den Browser ein Testbild rendern; mit readPixels() werden die Pixeldaten ausgelesen.
Sie können BrowserLeaks, aufrufen, auf WebGL Report klicken und Ihren einzigartigen Fingerabdruck sehen. Er sieht so aus:
Nachfolgend finden Sie ein Beispiel für ein Skript, das Websites verwenden. Sie können es auch zu Testzwecken einsetzen, etwa für Diagnosen, Fehlerberichte, Kompatibilitätstests und mehr. Führen Sie das Skript nur auf Geräten aus, die Ihnen gehören, oder nachdem Sie eine ausdrückliche Einwilligung erhalten haben. Verwenden Sie das Skript nicht zur Nachverfolgung oder Deanonymisierung. Behandeln Sie die Ergebnisse als sensible Daten und geben Sie sie nicht ohne Genehmigung an Dritte weiter. DataImpulse übernimmt keine Verantwortung für die rechtswidrige Nutzung des Skripts.
Schritt 1. Die WebGL-Umgebung starten
// Lightweight FNV-1a hash for strings/byte arrays (synchronous, simple)
function fnv1aHashFromBytes(bytes) {
let h = 0x811c9dc5 >>> 0;
for (let i = 0; i < bytes.length; i++) {
h ^= bytes[i];
// multiply by FNV prime (mod 2^32)
h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;
}
return ('00000000' + (h >>> 0).toString(16)).slice(-8);
}
function fnv1aHashFromString(s) {
const bytes = new Uint8Array(s.length);
for (let i = 0; i < s.length; i++) bytes[i] = s.charCodeAt(i) & 0xff;
return fnv1aHashFromBytes(bytes);
}
// Create an (optionally hidden) canvas and return WebGLRenderingContext / WebGL2RenderingContext
function createWebGLContext(opts = {webgl2Preferred: true, preserveDrawingBuffer: false}) {
const canvas = document.createElement('canvas');
canvas.width = 256; canvas.height = 256;
// optionally keep canvas off-DOM so it stays invisible
canvas.style.display = 'none';
document.body && document.body.appendChild(canvas); // append only if available
let gl = null;
if (opts.webgl2Preferred) {
try { gl = canvas.getContext('webgl2', {preserveDrawingBuffer: opts.preserveDrawingBuffer}); } catch (e) {}
}
if (!gl) {
try { gl = canvas.getContext('webgl', {preserveDrawingBuffer: opts.preserveDrawingBuffer}) || canvas.getContext('experimental-webgl'); } catch (e) {}
}
return {gl, canvas};
}
Dieser Abschnitt erstellt ein unsichtbares Canvas, das beim Browsen im Hintergrund ausgeführt wird, und legt dessen Auflösung fest. Wenn WebGL 2 nicht unterstützt wird, fällt es zudem sauber auf WebGL zurück.
Schritt 2. Hardwareinformationen abrufen
function getWebGLHardwareInfo(gl) {
const info = {};
// Standard parameters
info.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
info.maxCombinedTextureImageUnits = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
info.maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
info.maxVertexUniformVectors = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);
info.maxFragmentUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
info.shaderPrecision = {
vertexHighFloat: gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT),
fragmentHighFloat: gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT)
};
// Try to get unmasked renderer/vendor (if browser exposes WEBGL_debug_renderer_info)
const dbg = gl.getExtension('WEBGL_debug_renderer_info');
if (dbg) {
info.unmaskedVendor = gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL);
info.unmaskedRenderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL);
} else {
info.unmaskedVendor = null;
info.unmaskedRenderer = null;
}
// Extensions list (useful fingerprinting signal)
info.extensions = gl.getSupportedExtensions() || [];
// Anisotropy (if available)
const extAniso = gl.getExtension('EXT_texture_filter_anisotropic') ||
gl.getExtension('MOZ_EXT_texture_filter_anisotropic') ||
gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic');
if (extAniso) {
const maxAniso = gl.getParameter(extAniso.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
info.maxAnisotropy = maxAniso;
}
return info;
}
Es sammelt verschiedene Angaben wie Hersteller, Modell, Speichergröße, maximale Texturgröße, Grenzen für Shader-Uniforms, unterstützte WebGL-Erweiterungen und weitere Daten zu Ihrer GPU.
Schritt 3. Shader-Genauigkeiten prüfen
function probeShaderPrecisions(gl) {
const precisions = {};
const shaderTypes = [
{type: gl.VERTEX_SHADER, name: 'vertex'},
{type: gl.FRAGMENT_SHADER, name: 'fragment'}
];
const levels = [{p: gl.LOW_FLOAT, name: 'low'}, {p: gl.MEDIUM_FLOAT, name: 'medium'}, {p: gl.HIGH_FLOAT, name: 'high'}];
for (const sh of shaderTypes) {
precisions[sh.name] = {};
for (const lv of levels) {
const pf = gl.getShaderPrecisionFormat(sh.type, lv.p);
precisions[sh.name][lv.name] = {rangeMin: pf.rangeMin, rangeMax: pf.rangeMax, precision: pf.precision};
}
}
return precisions;
}
Websites fragen die GPU anschließend, welche Genauigkeitsstufen für Gleitkommaoperationen und Fragment-Shader unterstützt werden, und erfassen deren Zahlenbereiche.
Nachdem ein Skript die Hardware- und Softwareinformationen gesammelt hat, folgt der nächste Schritt: das Bild-Rendering.
Schritt 4. Rendering einer Testszenen
// Simple shader pair: position-only vertex shader and color-fragment that depends on coords
const VERT = `#version 300 es
in vec2 a_pos;
out vec2 v_uv;
void main() {
v_uv = a_pos * 0.5 + 0.5;
gl_Position = vec4(a_pos, 0.0, 1.0);
}`;
const FRAG = `#version 300 es
precision highp float;
in vec2 v_uv;
out vec4 outColor;
void main() {
// deterministic function of coordinates that will exercise GPU math
float r = sin(v_uv.x * 123.456) * 0.5 + 0.5;
float g = cos(v_uv.y * 78.9) * 0.5 + 0.5;
float b = fract((v_uv.x + v_uv.y) * 9876.54321);
outColor = vec4(r, g, b, 1.0);
}`;
function createProgramWebGL2(gl, vertSrc, fragSrc) {
function compile(src, type) {
const s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
const err = gl.getShaderInfoLog(s);
gl.deleteShader(s);
throw new Error('Shader compile error: ' + err);
}
return s;
}
const vs = compile(vertSrc, gl.VERTEX_SHADER);
const fs = compile(fragSrc, gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
const err = gl.getProgramInfoLog(program);
throw new Error('Program link error: ' + err);
}
gl.deleteShader(vs);
gl.deleteShader(fs);
return program;
}
function renderTestAndHash(gl, canvas) {
const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext;
if (!isWebGL2) {
// For WebGL1 we'd need slightly different shaders (no #version, use attribute/varying)
// but the concept is the same. For clarity this example uses WebGL2 if available.
console.warn('Example uses WebGL2 for deterministic shader pipeline; falling back may require shader edits.');
}
// Create program & buffer
const prog = createProgramWebGL2(gl, VERT, FRAG);
gl.useProgram(prog);
const posLoc = gl.getAttribLocation(prog, 'a_pos');
const quad = new Float32Array([
-1, -1,
1, -1,
-1, 1,
1, 1
]);
const vb = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
gl.enableVertexAttribArray(posLoc);
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
// Render to the canvas
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);
const t0 = performance.now();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.finish(); // ensure rendering completes
const t1 = performance.now();
const renderTime = t1 - t0; // render timing in ms
// Read pixels
const px = new Uint8Array(canvas.width * canvas.height * 4);
gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, px);
const pixelHash = fnv1aHashFromBytes(px);
// Clean up (optional)
gl.deleteBuffer(vb);
gl.deleteProgram(prog);
return {pixelHash, renderTime};
}
Das Skript fordert Ihren Browser auf, eine 2D- oder 3D-Szene mit bestimmten Farbtönen, Farbverläufen oder Effekten darzustellen. Anschließend liest es Pixel-Bytes aus, ermittelt Pixelfarben, Bildtextur, Schattierung und Farbverläufe, berechnet einen Hash dieser Werte und misst die Rendering-Zeit.
Schritt 5. Daten zu einem Fingerabdruck zusammenführen
function collectWebGLFingerprint(opts = {}) {
const {gl, canvas} = createWebGLContext({webgl2Preferred: true, preserveDrawingBuffer: true});
if (!gl) throw new Error('No WebGL available');
const hw = getWebGLHardwareInfo(gl);
const precisions = probeShaderPrecisions(gl);
// optional: probe more capabilities
const supportsFloatTextures = !!gl.getExtension('OES_texture_float') || !!gl.getExtension('EXT_color_buffer_float');
// Render test and get pixel hash + timing
const {pixelHash, renderTime} = renderTestAndHash(gl, canvas);
// Combine into a fingerprint string
const parts = [
navigator.userAgent || '',
hw.unmaskedVendor || '',
hw.unmaskedRenderer || '',
hw.maxTextureSize,
hw.maxCombinedTextureImageUnits,
hw.maxVertexAttribs,
supportsFloatTextures ? 'floatTex' : '',
hw.extensions ? hw.extensions.join(',') : '',
JSON.stringify(precisions),
pixelHash,
String(Math.round(renderTime)) // include rounded render time
];
const raw = parts.join('|');
const fingerprint = fnv1aHashFromString(raw);
// Return a readable object
return {
fingerprint,
raw,
components: {
ua: navigator.userAgent,
hardware: hw,
precisions,
pixelHash,
renderTime
}
};
}
// Example usage:
try {
const fp = collectWebGLFingerprint();
console.log('WebGL fingerprint:', fp.fingerprint);
console.log('Components:', fp.components);
} catch (e) {
console.error('Could not collect WebGL fingerprint:', e);
}
Zum Schluss ruft das Skript alle vorherigen Schritte auf, führt sämtliche gewonnenen Daten in einer langen Zeichenfolge zusammen und hasht sie erneut, um eine kompaktere und nutzbare Fingerabdruck-ID zu erstellen.
Der gesamte Prozess dauert Millisekunden und bleibt für Sie unsichtbar. Nachdem Websites Ihre Fingerabdrücke erfasst haben, speichern sie diese und vergleichen sie mit internen Datenbanken oder senden sie zur Analyse an Anti-Bot-Dienste. Entspricht ein Fingerabdruck einem bekannten Bot oder einem verdächtigen Nutzer, droht Ihnen eine Sperre.
Herausforderungen beim WebGL-Spoofing
Es gibt mehrere Gründe, weshalb die Anpassung an Traffic-Richtlinien schwierig sein kann.
- Unterschiede im Rendering-Verhalten der GPU sind für das menschliche Auge möglicherweise unsichtbar, für Websites jedoch offensichtlich und über verschiedene Seiten hinweg konsistent. Cookies zu löschen oder den Inkognito-Modus zu nutzen, hilft nicht.
- Das Rendering basiert auf Daten der physischen Hardware, die sich JavaScript-Änderungen und Browsererweiterungen entziehen.
- Sie können WebGL-Parameter bei jedem Laden einer Seite ändern. Wenn Ihre GPU jedoch angeblich von Intel ist, aber wie NVIDIA rendert, erkennen Websites diese Inkonsistenz. Das genügt, um Anti-Bot-Systeme auszulösen.
- Die meisten modernen Erkennungssysteme entdecken Versuche, die WebGL API zu manipulieren.
Heißt das, dass WebGL-Fingerprinting nicht zu umgehen ist? Nein, es gibt mehrere Techniken, die tatsächlich funktionieren. Zunächst aber das Wichtigste.
Ist das Spoofing von WebGL-Fingerabdrücken legal?
Sie haben das Recht, Ihre Privatsphäre zu schützen. Deshalb wäre es falsch zu behaupten, das Spoofing eines WebGL-Fingerabdrucks sei illegal. Es wird auch zu Testzwecken genutzt. Wer Spoofing jedoch für Betrug einsetzt oder damit die Terms of Service einer Website verletzt, handelt rechtswidrig. Lesen Sie stets die ToS und vermeiden Sie jede illegale Handlung, die die Privatsphäre anderer beeinträchtigen könnte. Die folgenden Informationen dienen ausschließlich Bildungszwecken. DataImpulse fordert Sie zu keinen Handlungen auf und übernimmt keine Verantwortung für mögliche Folgen.
Bewährte Methoden zum Spoofing von WebGL-Fingerabdrücken
- Verwenden Sie Headless-Browser mit zusätzlichen Bibliotheken
Beliebte Tools wie Playwright oder Selenium können, ergänzt durch Tools wie Playwright Stealth oder Undetected Chrome Driver, Parameter wie Bildschirmgröße und andere Werte leicht verändern. Sie müssen jedoch darauf achten, dass gefälschte Variablen und gerenderte Bilder zueinander passen. Bei Projekten im großen Maßstab oder beim Versuch, Websites mit dem neuesten Bot-Erkennungsalgorithmus zu scrapen, funktioniert diese Methode nicht. Dasselbe gilt für Browsererweiterungen wie WebGL Fingerprint Defender oder CanvasBlocker. Sie fangen Aufrufe der WebGL API ab und geben veränderte Daten zurück, doch das gerenderte Bild kann weiterhin davon abweichen.
- GPU-Virtualisierung einsetzen
Sie können die GPU und/oder Treiber des Browsers anders erscheinen lassen als eine echte physische GPU. Dafür gibt es mehrere Ansätze: Ersetzen Sie beispielsweise eine echte GPU durch einen Software-Renderer wie Switch Shader oder nutzen Sie virtuelle Maschinen mit unterschiedlichen GPU-Treibern. Wenn Ihr Budget knapp ist oder Ihnen fundierte technische Kenntnisse fehlen, sollten Sie diese Methoden jedoch gut abwägen. Auch die Skalierung Ihrer Scraping-Projekte kann anspruchsvoll sein.
- Statische APIs anfragen
Diese Methode funktioniert, wenn Sie öffentliche Daten scrapen und die Zielwebsite eine öffentliche oder verborgene API bereitstellt, die JSON zurückgibt. Bei geschützten dynamischen Websites ist das keine Option, in anderen Fällen aber eine erwägenswerte Wahl, da API-Endpunkte in der Regel weniger geschützt sind.
- WebGL deaktivieren
Durch das Deaktivieren von WebGL werden alle primären Signale für WebGL-Fingerprinting unterbunden: Hersteller/Renderer, Erweiterungen, Genauigkeit, Pixel-Hashes und Rendering-Zeiten.
So deaktivieren Sie WebGL
Chrome
Methode 1 – über Chrome Flags:
Geben Sie in die Adressleiste chrome://flags ein, drücken Sie die Eingabetaste und wählen Sie “WebGL deaktivieren” oder –disable-webgl aus. Setzen Sie das Flag auf “Disabled”. Starten Sie Chrome neu, damit die Änderungen wirksam werden.
Methode 2 – über die Befehlszeile:
Klicken Sie mit der rechten Maustaste auf das Google-Chrome-Symbol und wählen Sie “Properties”. Suchen Sie die Zeile “Target”. Sie sollte mit etwas wie chrome.exe. Fügen Sie ganz am Ende der Zeile ein Leerzeichen hinzu und geben Sie –disable-webgl ein. Klicken Sie auf “Apply” > “OK”.
Firefox
Geben Sie in die Adressleiste about:config ein und drücken Sie die Eingabetaste. Falls eine Warnung erscheint, bestätigen Sie sie. Suchen Sie nach webgl.disable. Doppelklicken Sie darauf und setzen Sie den Wert auf true.
Safari
Öffnen Sie die Safari-Einstellungen, wechseln Sie zum Tab “Advanced” und wählen Sie “Develop” (falls verfügbar). Gehen Sie zu Experimental Features und suchen Sie die Option für WebGL via Metal. Deaktivieren Sie das Kontrollkästchen und starten Sie den Browser neu.
Seien Sie jedoch vorsichtig, denn viele Websites funktionieren mit deaktiviertem WebGL möglicherweise nicht korrekt.
Schwachstellen beim WebGL-Fingerprinting ausnutzen
Sie können einige kleine Tricks anwenden. Skripte speichern Ergebnisse beispielsweise oft im Cache und verwenden sie erneut, statt sie von Grund auf neu zu berechnen. Sie können dies erkennen und entweder Ihre Umgebung ändern, bevor der Cache wiederverwendet wird, um eine Zuordnung zu einer zuvor erfassten Identität zu verhindern, oder eine Website dazu bringen, einen Wert neu zu berechnen.
Erkennung:
// Helper: run the fingerprinting routine and return {time, result}
async function runFingerprintTrial(triggerFn) {
const t0 = performance.now();
const result = await triggerFn(); // should return fingerprint/hash if available
const time = performance.now() - t0;
return { time, result };
}
async function detectCachingRobust(triggerFingerprinting, trials = 5) {
const runs = [];
for (let i = 0; i < trials; i++) {
// small delay to reduce micro-scheduling bias
if (i > 0) await new Promise(r => setTimeout(r, 30));
runs.push(await runFingerprintTrial(triggerFingerprinting));
}
// compute median time
const times = runs.map(r => r.time).sort((a,b) => a-b);
const medianTime = times[Math.floor(times.length/2)];
// compare first vs median of later runs
const firstTime = runs[0].time;
const laterMedian = times.slice(1).length ? times.slice(1)[Math.floor((times.length-1)/2)] : medianTime;
// check result stability (if trigger returns a fingerprint/hash)
const results = runs.map(r => r.result);
const allSame = results.every(x => x === results[0]);
// simple heuristic: if first run is much slower *and* results identical, likely cached
const speedRatio = firstTime / (laterMedian || 1);
const likelyCached = (speedRatio > 5) && allSame;
return {
runs,
medianTime,
firstTime,
laterMedian,
speedRatio,
results,
allSame,
likelyCached
};
}
Eine neue Umgebung erzwingen:
function newWebGLContext(w=256,h=256) {
const c = document.createElement('canvas');
c.width = w; c.height = h;
const gl = c.getContext('webgl2') || c.getContext('webgl') || c.getContext('experimental-webgl');
return {c, gl};
}
Neuberechnung erzwingen:
localStorage.removeItem('fp_token'); // only if you can identify it
// or flush likely storage (be careful: may break site)
localStorage.clear();
indexedDB.deleteDatabase('site-db-name'); // needs precise names
Ein weiterer Ansatz besteht darin, zu erkennen, wann eine Seite ein Fingerprinting-Skript hinzufügt, und zuvor ein Spoofing-Skript auszuführen. Beachten Sie jedoch, dass dies leicht erkennbar ist und das Verhalten der Seite stören kann. Diese Methode eignet sich eher für Tests oder defensive Zwecke.
// Robust script interception (best run at document_start)
(function() {
if (window.__scriptInterceptorInstalled) return;
window.__scriptInterceptorInstalled = true;
// Your spoofing routine — define this to patch WebGL or other APIs.
function injectSpoofing() {
try {
// Example: block debug info (replace with your real routine)
const origGetExt = WebGLRenderingContext.prototype.getExtension;
WebGLRenderingContext.prototype.getExtension = function(name) {
if (name === 'WEBGL_debug_renderer_info') return null;
return origGetExt.call(this, name);
};
// mark that spoofing ran
window.__spoofingInjected = true;
} catch (e) {
// swallow errors — don't break page
console.error('injectSpoofing error', e);
}
}
// Helper: decide whether a script looks like fingerprinting (tweak to match)
function looksLikeFingerprintScript(srcOrContent) {
if (!srcOrContent) return false;
const s = String(srcOrContent).toLowerCase();
return s.includes('fingerprint') || s.includes('fingerprinting') || s.includes('fingerprintjs') || s.includes('fingerprint2');
}
// 1) Hook HTMLScriptElement.prototype.src property (setter)
try {
const proto = HTMLScriptElement.prototype;
const srcDesc = Object.getOwnPropertyDescriptor(proto, 'src');
if (srcDesc && srcDesc.configurable) {
Object.defineProperty(proto, 'src', {
configurable: true,
enumerable: srcDesc.enumerable,
get: function() { return srcDesc.get.call(this); },
set: function(val) {
try {
// If the script's src looks suspicious, inject before setting
if (looksLikeFingerprintScript(val) && !window.__spoofingInjected) {
injectSpoofing();
}
} catch (e) { /* ignore */ }
return srcDesc.set.call(this, val);
}
});
}
} catch (e) {
// non-fatal
}
// 2) Hook setAttribute on script elements (covers element.setAttribute('src', ...))
try {
const origSetAttr = HTMLScriptElement.prototype.setAttribute;
HTMLScriptElement.prototype.setAttribute = function(name, value) {
try {
if ((name + '').toLowerCase() === 'src' && looksLikeFingerprintScript(value) && !window.__spoofingInjected) {
injectSpoofing();
}
} catch (e) {}
return origSetAttr.call(this, name, value);
};
} catch (e) {}
// 3) As a fallback, monitor append/insert to catch scripts that already had src set
try {
const origAppend = Node.prototype.appendChild;
Node.prototype.appendChild = function(node) {
try {
if (node && node.tagName && node.tagName.toLowerCase() === 'script') {
const src = node.src || node.getAttribute && node.getAttribute('src');
if (looksLikeFingerprintScript(src) && !window.__spoofingInjected) {
injectSpoofing();
}
}
} catch (e) {}
return origAppend.call(this, node);
};
const origInsertBefore = Node.prototype.insertBefore;
Node.prototype.insertBefore = function(node, ref) {
try {
if (node && node.tagName && node.tagName.toLowerCase() === 'script') {
const src = node.src || node.getAttribute && node.getAttribute('src');
if (looksLikeFingerprintScript(src) && !window.__spoofingInjected) {
injectSpoofing();
}
}
} catch (e) {}
return origInsertBefore.call(this, node, ref);
};
} catch (e) {}
// 4) Small DOM observer as an extra safety net (lightweight)
try {
const obs = new MutationObserver((mutations) => {
for (const m of mutations) {
for (const n of m.addedNodes || []) {
try {
if (n && n.tagName && n.tagName.toLowerCase() === 'script') {
const src = n.src || (n.getAttribute && n.getAttribute('src')) || n.textContent;
if (looksLikeFingerprintScript(src) && !window.__spoofingInjected) {
injectSpoofing();
obs.disconnect();
return;
}
}
} catch (e) {}
}
}
});
obs.observe(document, { childList: true, subtree: true });
} catch (e) {}
// If the page already has script tags at start, scan them now
try {
const scripts = document.getElementsByTagName('script');
for (let i = 0; i < scripts.length; i++) {
const s = scripts[i];
const src = s.src || s.getAttribute && s.getAttribute('src') || s.textContent;
if (looksLikeFingerprintScript(src) && !window.__spoofingInjected) {
injectSpoofing();
break;
}
}
} catch (e) {}
})();
WebGL-Umgebungen verschiedener Seiten können sich zudem nicht gegenseitig sehen. Sie können isolierte Kontexte erstellen, damit Websites Ihre Fingerabdrücke nicht seitenübergreifend zuordnen können.
WebGL im Vergleich zu Canvas
WebGL-Fingerprinting und Canvas-Fingerprinting werden oft synonym verwendet, und tatsächlich sind sie eng miteinander verwandt. Sie sind jedoch nicht zu 100% identisch.
Canvas-Fingerprinting analysiert, wie Browser 2D-Grafiken mit HTML5 Canvas rendern. Die Rendering-Ergebnisse hängen hauptsächlich vom Grafik-Stack und der Rendering-Engine des Browsers ab. Daher lässt es sich leichter spoofen.
WebGL-Fingerprinting analysiert, wie ein Browser sowohl 2D- als auch 3D-Grafiken rendert. Die Darstellungsergebnisse hängen von Hardwaremerkmalen ab, was diese Methode aussagekräftiger und schwieriger zu umgehen macht.
Zusammenfassung
Nachdem Sie nun die Herausforderungen beim Spoofing von WebGL-Fingerabdrücken kennen, denken Sie vielleicht, dass Sie vor zehn Minuten besser dran waren, als Sie noch nichts davon wussten. Ihr Ziel ist jedoch nicht, unsichtbar zu sein. Sie müssen lediglich wie ein “normaler Nutzer” wirken. Dafür muss Ihr Fingerabdruck realistisch aussehen, innerhalb einer Sitzung konsistent sein und sich von Sitzung zu Sitzung ändern. Das ist durchaus machbar. Erfolgreiches Web Scraping ist andererseits nur möglich, wenn Sie Vertraulichkeit auf allen Ebenen wahren und Multi-Login-Browser, TLS-Spoofing-Lösungen, Proxys, usw. einsetzen. All diese Tools und Ansätze ergänzen einander und helfen Ihnen, unauffällig zu bleiben. DataImpulse bietet genau das Richtige für Ihre Privatsphäre und Anonymität: rechtmäßig bezogene, auf der Whitelist stehende Proxys für universelle Scraping-Anforderungen sowie einen menschlichen 24/7-Support, damit Sie Daten ohne Unterbrechung sammeln können. Klicken Sie auf “Jetzt testen” oder kontaktieren Sie uns unter [email protected], um loszulegen.

