In this Article
Le fingerprinting WebGL est une technique d’identification largement utilisée par les systèmes anti-bot pour détecter les activités automatisées. Comme elle exploite des signaux matériels, elle est assez difficile à contourner et représente une difficulté supplémentaire pour les professionnels du web scraping. Il existe toutefois des moyens de rester discret et de collecter des données : lisez la suite pour en savoir plus.
Qu’est-ce que WebGL ? Explication détaillée
WebGL, ou Web Graphics Library, est une API JavaScript. Les navigateurs l’utilisent pour afficher des graphismes 2D et 3D dynamiques sans avoir à installer de plugins. Pour effectuer ces tâches de rendu, l’API s’appuie fortement sur le GPU, ou Graphics Processing Unit. Aujourd’hui, les sites web utilisent abondamment WebGL pour les effets visuels, les jeux et les interfaces graphiques complexes. En pratique, WebGL 2 est en train de s’imposer, car il offre davantage de fonctionnalités. Les navigateurs modernes, comme Chrome, Edge et Safari, prennent en charge WebGL 2 à 95-99 %, tandis que les navigateurs plus anciens et headless ne le prennent pas toujours en charge.
Comme il existe des centaines de GPU et que même les modèles d’un même fabricant diffèrent radicalement, une même image peut être rendue différemment. De plus, le navigateur, les pilotes installés et même les variations matérielles, comme la manière dont le GPU et la carte mère sont connectés, peuvent aussi influencer le résultat. C’est comme entrer dans un magasin d’électronique et voir plusieurs dizaines de téléviseurs afficher la même publicité, avec des images pourtant légèrement différentes. C’est sur ce principe que repose le fingerprinting WebGL. Notez que le fingerprinting WebGL n’a lieu que lorsque JavaScript intervient. Une page HTML statique ne peut pas l’exécuter.
Le fingerprinting WebGL : un aperçu étape par étape
Dans les grandes lignes, le processus se déroule ainsi :
- Un site web crée un élément <canvas> dissimulé dans le HTML de la page. Il initialise l’environnement de rendu WebGL.
- JavaScript utilise des appels gl.getParameter() pour extraire les caractéristiques du GPU telles que le fabricant et le modèle.
- Un script de fingerprinting demande à un navigateur de rendre une image de test, et readPixels() est utilisé pour extraire les données de pixels.
Vous pouvez visiter BrowserLeaks, cliquer sur WebGL Report et voir votre empreinte unique. Elle ressemble à ceci :
Ci-dessous, vous trouverez un exemple de script que les sites web peuvent utiliser. Vous pouvez aussi l’utiliser à des fins de test, comme le diagnostic, les rapports de bugs, les tests de compatibilité, etc. N’oubliez pas d’exécuter le script uniquement sur vos propres appareils ou après avoir obtenu un consentement explicite. Évitez d’utiliser le script à des fins de suivi ou de désanonymisation. Traitez les résultats comme des données sensibles et ne les partagez pas avec des tiers sauf autorisation. DataImpulse n’assume aucune responsabilité en cas d’utilisation illégale du script.
Étape 1. Lancer l’environnement WebGL
// 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};
}
Ce fragment crée un canvas invisible qui s’exécute en arrière-plan pendant votre navigation et en définit la résolution. De plus, si WebGL 2 n’est pas pris en charge, il utilisera WebGL comme solution de repli.
Étape 2. Obtenir les informations matérielles
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;
}
Il collecte divers détails tels que le fabricant, le modèle, la quantité de mémoire, la taille maximale des textures, les limites des uniformes des shaders, l’extension WebGL prise en charge et d’autres données concernant votre GPU.
Étape 3. Vérifier la précision des shaders
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;
}
Les sites web demandent ensuite au GPU quels niveaux de précision sont pris en charge pour les opérations en virgule flottante et les fragment shaders, puis enregistrent les plages numériques correspondantes.
Maintenant que le script a fini de collecter les informations matérielles et logicielles, il passe à l’étape suivante : le rendu d’image.
Étape 4. Tester le rendu de la scène
// 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};
}
Le script demande à votre navigateur d’afficher une scène 2D ou 3D pouvant contenir des nuances, des dégradés ou des effets spécifiques. Il lit ensuite les octets de pixels et apprend des informations sur les couleurs des pixels, la texture de l’image, l’ombrage et les dégradés, calcule le hash de ces valeurs et mesure le temps de rendu.
Étape 5. Combiner les données dans une empreinte
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);
}
Enfin, le script appelle toutes les étapes précédentes, combine toutes les données obtenues en une seule longue chaîne et la hache à nouveau pour créer un identifiant d’empreinte plus compact et exploitable.
L’ensemble de ce processus se déroule en quelques millisecondes et reste invisible pour vous. Après avoir collecté vos empreintes, les sites web les stockent et les comparent à des bases de données internes, ou les envoient à des services anti-bot pour analyse. Si une empreinte correspond à un bot connu ou à un utilisateur suspect, vous risquez d’être bloqué.
Les défis du spoofing WebGL
Il existe plusieurs raisons pour lesquelles faire correspondre vos signaux à ceux du trafic attendu peut s’avérer délicat.
- Les différences de comportement de rendu du GPU peuvent être invisibles à l’œil humain, mais elles sont évidentes pour les sites web et restent cohérentes d’une page à l’autre. Effacer les cookies ou utiliser le mode navigation privée n’aide pas.
- Le rendu repose sur des données provenant du matériel physique, hors de portée des modifications JavaScript et des extensions de navigateur.
- Vous pouvez modifier les paramètres WebGL à chaque chargement de page ; toutefois, si vous faites passer votre GPU pour un Intel alors qu’il rend les images comme un NVIDIA, les sites web détecteront l’incohérence, et cela suffit à déclencher les systèmes anti-bot.
- La majorité des systèmes de détection modernes repèrent les tentatives de manipulation de l’API WebGL.
Cela signifie-t-il qu’il n’y a aucun moyen de contourner le fingerprinting WebGL ? Non, plusieurs techniques fonctionnent réellement. Mais procédons dans l’ordre.
Le spoofing d’empreinte WebGL est-il légal ?
Vous avez le droit de protéger votre vie privée : il serait donc inexact d’affirmer que le spoofing d’une empreinte WebGL est intrinsèquement illégal. Il est aussi utilisé à des fins de test. Cependant, recourir au spoofing pour commettre une fraude peut être illégal et peut aussi enfreindre les conditions d’utilisation des sites web. Vous devez toujours lire les CGU et éviter toute action illégale susceptible de nuire à la vie privée d’autrui. Les informations suivantes sont fournies uniquement à des fins éducatives. DataImpulse ne vous encourage à entreprendre aucune action et n’assume aucune responsabilité quant aux conséquences possibles.
Des méthodes éprouvées pour spoofer des empreintes WebGL
- Utiliser des navigateurs headless avec des bibliothèques supplémentaires
Des outils populaires comme Playwright ou Selenium, épaulés par des outils comme Playwright Stealth ou Undetected Chrome Driver, peuvent modifier légèrement certains paramètres, comme la taille de l’écran. Vous devez toutefois veiller à ce que les fausses variables et les images rendues concordent. Cette méthode ne convient pas aux projets à grande échelle ni au scraping de sites web qui utilisent les algorithmes de détection de bots les plus récents. Il en va de même pour les extensions de navigateur comme WebGL Fingerprint Defender ou CanvasBlocker. Elles interceptent les appels de l’API WebGL et renvoient des données modifiées, mais l’image rendue pourrait tout de même ne pas correspondre.
- Opter pour la virtualisation du GPU
Vous pouvez faire en sorte que le GPU utilisé par le navigateur et/ou ses pilotes paraissent différents de ceux d’un GPU physique réel. Il existe plusieurs approches à adopter, par exemple remplacer un vrai GPU par un moteur de rendu logiciel comme Switch Shader ou utiliser des machines virtuelles avec différents pilotes GPU. En revanche, si votre budget est serré ou si vous manquez de solides compétences techniques, réfléchissez-y à deux fois avant d’adopter ces méthodes. De plus, faire évoluer vos projets de scraping à grande échelle peut s’avérer difficile.
- Interroger des API statiques
Cette méthode fonctionne si vous scrapez des données publiques et que le site web cible fournit une API publique ou cachée qui renvoie du JSON. Sur les sites dynamiques protégés, ce n’est pas une option, mais dans d’autres cas, c’est une option intéressante, car les endpoints d’API sont généralement moins protégés.
- Désactiver WebGL
Désactiver WebGL coupe tous les principaux signaux du fingerprinting WebGL (vendor/renderer, extensions, précision, hashs de pixels, temps de rendu).
Comment désactiver WebGL
Chrome
Méthode 1 – via les Chrome Flags :
Dans la barre d’adresse, tapez chrome://flags, appuyez sur Entrée et sélectionnez “Disable WebGL” ou –disable-webgl. Réglez le flag sur “Disabled”. Pour activer les changements, relancez Chrome.
Méthode 2 – via la ligne de commande :
Faites un clic droit sur l’icône de Google Chrome et allez dans “Propriétés”. Recherchez la ligne “Cible” . Elle devrait se terminer par quelque chose comme chrome.exe. Tout à la fin de la ligne, ajoutez un espace et tapez –disable-webgl. Cliquez sur “Appliquer” > “OK”.
Firefox
Dans la barre d’adresse, tapez about:config et appuyez sur Entrée. Si un avertissement apparaît, acceptez-le. Cherchez webgl.disable. Double-cliquez et réglez sa valeur sur true.
Safari
Allez dans les préférences de Safari, ouvrez l’onglet “Avancé” et sélectionnez “Développement” (si disponible). Accédez aux fonctionnalités expérimentales et trouvez l’option pour WebGL via Metal. Décochez la case et redémarrez le navigateur.
Soyez toutefois prudent, car de nombreux sites web pourraient ne pas fonctionner correctement lorsque WebGL est désactivé.
Exploiter les vulnérabilités du fingerprinting WebGL
Vous pouvez recourir à quelques astuces. Par exemple, les scripts mettent souvent les résultats en cache et les réutilisent au lieu de tout recalculer. Vous pouvez le détecter et soit modifier votre environnement avant que le cache ne soit réutilisé (pour éviter d’être associé à une identité précédemment enregistrée), soit forcer un site à recalculer une valeur.
Détecteur :
// 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
};
}
Forcer un nouvel environnement :
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};
}
Forcer le recalcul :
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
Une autre approche consiste à détecter le moment où une page ajoute un script de fingerprinting et à exécuter un script de spoofing au préalable. Sachez toutefois que cela est facilement détectable et peut perturber le comportement de la page ; cette méthode convient davantage à des fins de test ou défensives.
// 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) {}
})();
De plus, les environnements WebGL de différentes pages ne peuvent pas communiquer entre eux. Vous pouvez créer des contextes isolés pour empêcher les sites web d’associer vos empreintes d’une page à l’autre.
WebGL vs Canvas
Le fingerprinting WebGL et le fingerprinting Canvas sont souvent employés de manière interchangeable, et il est vrai qu’ils sont étroitement liés. Ils ne sont toutefois pas identiques à 100 %.
Le fingerprinting Canvas analyse la manière dont les navigateurs rendent des graphismes 2D à l’aide de HTML5 Canvas. Les résultats du rendu dépendent principalement de la pile graphique du navigateur et du moteur de rendu. Il est de ce fait plus facile à usurper.
Le fingerprinting WebGL analyse la manière dont un navigateur rend des graphismes 2D et 3D. Les résultats d’affichage dépendent des caractéristiques matérielles, ce qui rend cette méthode plus informative et plus difficile à contourner.
Résumé
Maintenant que vous connaissez les défis liés au spoofing du fingerprinting WebGL, vous pourriez vous dire que vous étiez mieux loti il y a dix minutes, quand vous ignoriez encore tout du sujet. Votre objectif n’est cependant pas d’être invisible : vous devez simplement ressembler à un “utilisateur ordinaire”. Pour cela, votre empreinte doit paraître réaliste, rester cohérente au sein d’une session et changer d’une session à l’autre. Et c’est tout à fait réalisable. En revanche, un web scraping réussi n’est possible que si vous préservez la confidentialité à tous les niveaux et employez des navigateurs multi-comptes, solutions de spoofing TLS, proxies, etc. Tous ces outils et approches se renforcent mutuellement et vous permettent de passer inaperçu. DataImpulse propose justement ce qu’il faut pour protéger votre confidentialité et votre anonymat : des proxies obtenus légalement et autorisés par liste blanche pour tous les besoins de scraping, ainsi qu’un service d’assistance humaine 24h/24 et 7j/7 pour que vous puissiez collecter des données sans interruption. Cliquez sur “Essayer maintenant” ou contactez-nous à l’adresse [email protected] pour commencer.

