Panoramica
Segnali derivati dalle funzionalità della piattaforma web, capacità CSS, font e altre caratteristiche del browser.
1. Fingerprinting dei Font
Meccanismo
I font vengono enumerati tramite diverse tecniche:
-
Misurazione CSS
@font-face: Crea testo, misura la sua larghezza con un font noto, poi prova a caricare un font di sistema. Se la larghezza cambia, il font esiste. -
Canvas
measureText: Approccio simile che utilizza canvas. -
document.fonts.check(): API moderna per verificare la disponibilità dei font.
Enumerazione basata su Flash (legacy, ancora usata): Flash può elencare tutti i font installati.
Esempio di Codice
// Rilevamento font basato su misurazione
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const text = 'mmmmmmmmmmlli'
function detectFont(font) {
ctx.font = `72px ${font}, monospace`
return ctx.measureText(text).width
}
// Confronta la larghezza con la baseline monospace per rilevare
Entropia
L'elenco dei font varia ampiamente:
| Piattaforma | Font Tipici | Unicità |
|---|---|---|
| Windows 11 stock | ~80 font | Media |
| macOS Ventura+ | ~120 font | Media |
| Linux (distro varia) | 10-500 font | Molto Alta |
| Font personalizzati installati | Qualsiasi | Molto Alta |
Mitigazione al Proxy
// Sovrascrivi la misurazione dei font per restituire valori coerenti
const originalMeasureText = CanvasRenderingContext2D.prototype.measureText
CanvasRenderingContext2D.prototype.measureText = function(text) {
const result = originalMeasureText.call(this, text)
// Arrotonda la larghezza per ridurre la precisione del rilevamento font
result.width = Math.round(result.width / 10) * 10
return result
}
Limitazione: Il rilevamento dei font è solo ridotto, non eliminato.
2. Supporto Funzionalità Browser (25+ vettori binari)
Meccanismo
Ogni browser supporta un sottoinsieme diverso di API web e funzionalità CSS. Collettivamente, questo crea un fingerprint browser+versione.
Funzionalità ad Alta Entropia
| Funzionalità | Chrome | Firefox | Safari |
|---|---|---|---|
| WebGL | Sì | Sì | Sì |
| WebGPU | Sì (flag) | No | No |
| WebUSB | Sì | No | No |
| Web Bluetooth | Sì | No | No |
| Web NFC | Android | No | No |
| Web Authentication | Sì | Sì | Sì |
| Web Assembly | Sì | Sì | Sì |
| Service Workers | Sì | Sì | Sì |
| Battery API | No | Sì | No |
| Speech Synthesis | Sì | Sì | Sì |
| GamePad API | Sì | Sì | Sì (parziale) |
| WebRTC | Sì | Sì | Sì |
| CSS Grid | Sì | Sì | Sì |
| CSS backdrop-filter | Sì | Sì | Sì |
| CSS Container Queries | Sì | Sì | Sì |
Entropia
Ogni funzionalità aggiunge ~1 bit. Con ~100 funzionalità testate, il massimo teorico è 100 bit, ma le funzionalità sono altamente correlate (entropia minima oltre la famiglia e versione del browser).
Entropia effettiva: ~8-12 bit (~256-4096 combinazioni).
Mitigazione
Non può essere fatto a livello di proxy: queste sono capacità intrinseche del browser. Il rilevamento delle funzionalità viene eseguito in JS prima che qualsiasi script iniettato possa essere eseguito (e anche se sovrascritto, il browser riporta comunque le capacità effettive da qualche parte).
3. Fingerprinting tramite Media Query CSS
Meccanismo
Le query CSS @media possono ricavare forzatamente le dimensioni dello schermo, DPI, profondità colore e altre proprietà senza JS:
@media (width: 1920px) { body::after { content: '1920' } }
@media (height: 1080px) { body::after { content: '1080' } }
@media (resolution: 1.5dppx) { body::after { content: '1.5' } }
@media (prefers-color-scheme: dark) { ... }
@media (prefers-reduced-motion: no-preference) { ... }
@media (hover: hover) { ... }
@media (pointer: fine) { ... }
Sfida per il Proxy
Il CSS viene eseguito prima di qualsiasi iniezione JS. Il proxy può:
- Analizzare il CSS nell'HTML della risposta e modificare le media query
- O fare affidamento sul fatto che i probe CSS-only devono esfiltrare dati (che richiede JS o una richiesta di rete)
Mitigazione reale: Blocca il percorso di esfiltrazione (JS o caricamento immagini) piuttosto che falsificare i valori CSS.
Elenco Media Query
| Query | Valori | Informazioni Rivelate |
|---|---|---|
| width | px | Larghezza schermo |
| height | px | Altezza schermo |
| aspect-ratio | ratio | Rapporto schermo |
| resolution | dppx | Densità pixel |
| color | bit | Profondità colore |
| color-gamut | srgb/p3/rec2020 | Spazio colore |
| prefers-color-scheme | light/dark | Tema OS |
| prefers-reduced-motion | no-preference/reduce | Impostazione OS |
| prefers-contrast | no-preference/more/less | Impostazione OS |
| prefers-reduced-transparency | no-preference/reduce | Impostazione OS |
| hover | none/hover | Dispositivo di input |
| pointer | none/coarse/fine | Dispositivo di input |
| any-hover | none/hover | Qualsiasi input |
| any-pointer | none/coarse/fine | Qualsiasi input |
| display-mode | fullscreen/standalone | Modalità PWA |
| prefers-color-gamut | srgb/p3 | Gamut display |
| dynamic-range | standard/high | Supporto HDR |
| inverted-colors | none/inverted | Accessibilità OS |
| monochrome | bit | Display monocromatico |
| forced-colors | none/active | Accessibilità |
| prefers-reduced-data | no-preference/reduce | Risparmio dati |
4. Fingerprinting ClientRects
Meccanismo
Element.getClientRects() restituisce valori leggermente diversi a seconda del SO, del browser e del rendering dei font:
const span = document.createElement('span')
span.textContent = 'mmmmmmmmmmlli'
document.body.appendChild(span)
const rects = span.getClientRects()
// rects[0].width varia per SO/browser/font
Mitigazione
Element.prototype.getClientRects = function() {
const rects = Element.prototype.__proto__.getClientRects.call(this)
return Array.from(rects).map(r => ({
...r,
width: Math.round(r.width / 10) * 10,
height: Math.round(r.height / 10) * 10
}))
}
5. Fingerprint Web Audio API
Vedi audio-fingerprinting.md per i dettagli.
6. Fingerprinting WebGPU
WebGPU fornisce informazioni strutturate sul dispositivo non precedentemente disponibili:
const adapter = await navigator.gpu.requestAdapter()
const info = await adapter.requestAdapterInfo()
// { vendor: "nvidia", architecture: "ampere", device: "..." }
// I limiti dell'adattatore espongono capacità GPU specifiche
const limits = adapter.limits
// maxTextureDimension2D, maxStorageBufferBindingSize, ecc.
// Set di funzionalità
adapter.features.has('texture-compression-bc')
adapter.features.has('shader-f16')
Dati Esposti
| Campo | Esempio | Identificabilità |
|---|---|---|
| vendor | "nvidia", "apple", "amd", "intel" | Bassa (4-5 valori) |
| architecture | "ampere", "rdna2", "tigerlake" | Media |
| device | "integrated-graphics", "Apple M3" | Media |
| driver | "460.32.03" | Alta |
| backend | "Metal", "Vulkan", "D3D12" | Bassa |
| type | "discrete-gpu", "integrated-gpu", "cpu" | Bassa |
| memoryHeaps | dimensione e conteggio | Alta |
| limits | 50+ valori di capacità | Molto Alta |
Mitigazione
// Blocca le informazioni dell'adattatore WebGPU
navigator.gpu.requestAdapter = async function() {
return null // o restituisci un adattatore fittizio minimo
}
Costo: Blocca WebGPU completamente, rompendo alcune app.
7. Persistenza Service Worker
Meccanismo
I Service Workers possono essere usati per identificare gli utenti tra sessioni:
// Rileva se un SW è installato
navigator.serviceWorker.getRegistrations().then(regs => {
if (regs.length > 0) console.log('SW trovato')
})
Mitigazione
navigator.serviceWorker.getRegistrations =
async () => []
8. Fingerprint Estensioni WebGL
WebGL espone un elenco di estensioni supportate che varia per GPU, driver e browser:
| Tipo Estensione | Conteggio | Esempio |
|---|---|---|
| WebGL standard | ~30 | OES_texture_float |
| WEBGL_* | ~15 | WEBGL_debug_renderer_info |
| EXT_* | ~15 | EXT_texture_filter_anisotropic |
| Specifiche del browser | ~5 | MOZ_WEBGL_* |
Entropia: L'insieme e il conteggio esatti delle estensioni crea un hash.
Mitigazione:
const originalGetExtension = WebGLRenderingContext.prototype.getExtension
WebGLRenderingContext.prototype.getExtension = function(name) {
if (name === 'WEBGL_debug_renderer_info') return null
if (name.startsWith('MOZ_')) return null
return originalGetExtension.call(this, name)
}
Conclusioni per Obscura
| Vettore | Controllo Proxy | Strategia di Mitigazione |
|---|---|---|
| Enumerazione font | Parziale | Arrotonda misurazioni, blocca Flash |
| Supporto funzionalità | Nessuno | Accetta: inerente al browser |
| Media query CSS | Parziale | Blocca esfiltrazione (DNS/network) |
| ClientRects | Parziale | Arrotonda valori tramite iniezione JS |
| WebGPU | Parziale | Blocca informazioni adattatore |
| Service Workers | Parziale | Sovrascrivi API di registrazione |
| Estensioni WebGL | Parziale | Filtra elenco estensioni |