Il sistema di rilevamento dei bot di TRACIO identifica browser automatizzati, strumenti headless e attacchi tramite script utilizzando un'architettura a due livelli: raccolta dei segnali lato client e analisi lato server. Rileva i principali framework di automazione, i browser headless, gli agenti di navigazione IA e i browser anti-rilevamento con falsi positivi quasi nulli, inserendo automaticamente nella allowlist i crawler legittimi dei motori di ricerca.
L'agente del browser raccoglie una serie di segnali specifici per i bot e di cross-validazione che alimentano le decisioni lato server. Gli ID dei segnali riportati di seguito sono illustrativi — gli ID interni non costituiscono un contratto pubblico stabile:
| Segnale | Descrizione |
|---|---|
s300 (webdriver) | Flag navigator.webdriver — impostato a true dai framework di automazione |
s301 (eval length) | eval.toString().length — Chrome/Edge: 33, Firefox: 37. Altri valori indicano strumentazione. |
s305 (bot composite) | Analizza window/document alla ricerca di 14 artefatti di framework di automazione |
s97 (headless markers) | Artefatti CDP, permessi di notifica, numero di plugin, dimensioni esterne |
s157 (automation scan) | Scansione completa per Selenium, Puppeteer, PhantomJS, Playwright e altri 10 |
s158 (iframe webdriver) | Crea un iframe nascosto e legge navigator.webdriver al suo interno. Individua gli strumenti che modificano il frame principale ma dimenticano gli iframe. |
s159 (native function) | Elimina Function e Object, verifica se i getter sono realmente nativi. Rileva la strumentazione basata su Proxy. |
s155 (window CRC32) | Scansione con hash CRC32 di ogni proprietà window per rilevare global di automazione iniettati |
s163 (devtools trap) | Trap del getter della console — rileva quando i DevTools sono attivamente aperti |
Il server esegue un insieme di rilevatori i cui output ponderati si combinano in un
punteggio bot. Il punteggio viene mappato su un verdetto tramite soglie — bot quando è ≥ 0.70,
suspicious quando è ≥ 0.30, altrimenti human — e un segnale hard-fail (come
navigator.webdriver) forza direttamente un verdetto bot. I verdetti bot recano
un'etichetta bot_type in formato libero.
Rilevatori rappresentativi e loro effetto:
| Rilevatore | Effetto |
|---|---|
| Flag webdriver | Hard-fail → bot (tipo webdriver) |
| Scansione automazione / framework composita | Peso elevato → bot (tipo {framework}) |
| Marker headless | Ponderato → bot (tipo headless) |
| Anomalia della lunghezza di eval | Ponderato → bot (tipo unknown) |
| Pattern UA di bad-bot | Ponderato → bot (tipo {label}) |
| Good bot verificato (reverse DNS) | Allowlist → human |
| Comportamentale (frequenza / entropia / interazione) | Ponderato → bot (tipo rateBot) |
| VM (Enterprise) · Emulatore · DevTools (Business+) | Segnali ponderati di dispositivo/manomissione |
Piano e disponibilità. Il rilevamento dei DevTools è attivo su Business ed Enterprise; il rilevamento delle VM è Enterprise; il rilevamento degli emulatori è attivo su tutti i piani. Tutti questi funzionano nell'agente web. Il rilevamento di root, jailbreak, app clonata/duale, Frida e reset di fabbrica dipende da segnali nativi mobile e non è efficace nel deployment solo-web (in sviluppo). Fare affidamento sui verdetti di automazione, headless, agente IA, anti-rilevamento, VM/emulatore e comportamentali, che sono pienamente attivi sul web.
Il rilevamento dei bot scrive un campo bot_result su ogni evento (e bot.result nel
payload del webhook).
bot_result è uno di tre valori canonici:
| Risultato | Descrizione |
|---|---|
human | Nessun indicatore di automazione trovato. Anche i crawler verificati dei motori di ricerca risolvono a human. |
bot | Rilevato accesso automatizzato o tramite script. Lo accompagna un'etichetta bot_type in formato libero. |
uncertain | Segnali misti o deboli — né chiaramente umano né chiaramente automatizzato. |
Questo viene mappato sul campo aziendale decision (real, fake o suspicious)
usato in tutta la dashboard, e su bot.result nel
payload del webhook.
"bot")bot_type è una stringa in formato libero. I valori seguenti sono esempi illustrativi di
ciò che i rilevatori emettono, non un enum esaustivo:
| Tipo | Metodo di rilevamento |
|---|---|
webdriver | navigator.webdriver è true |
selenium | Rilevate proprietà window/document specifiche di Selenium |
puppeteer | Corrispondenza con indicatori headless di Puppeteer/Chromium |
playwright | Rilevati marker o stringa UA specifici di Playwright |
headless | Attivati 2 o più degli 11 marker headless |
phantomjs | Rilevati global di PhantomJS (callPhantom, _phantom) |
nightmare | Rilevati global di NightmareJS |
unknown | Anomalia della lunghezza di eval o altri indicatori di automazione non specifici |
rateBot | L'analisi comportamentale della frequenza ha superato le soglie |
Il rilevamento più diretto. Tutti i principali framework di automazione impostano navigator.webdriver = true come da specifica WebDriver. Questo viene verificato sia nel frame principale (s300) sia in un iframe nascosto (s158) per individuare gli strumenti che modificano solo il frame principale.
Scansione completa delle proprietà window e document alla ricerca di artefatti specifici dei framework:
| Framework | Proprietà rilevate |
|---|---|
| Selenium | _Selenium_IDE_Recorder, _selenium, calledSelenium, __selenium_evaluate, $cdc_* (ChromeDriver) |
| Puppeteer | domAutomation, domAutomationController, UA HeadlessChrome |
| Playwright | __playwright, flag automation-controlled |
| PhantomJS | callPhantom, _phantom |
| NightmareJS | __nightmare, nightmare |
| CefSharp | CefSharp |
| Awesomium | awesomium |
| WebDriverIO | wdioElectron |
| Cypress | Proprietà window __cypress |
La scansione utilizza anche un pattern regex /^([a-z]){3}_.*_(Array|Promise|Symbol)$/ per rilevare i global helper iniettati da Selenium.
Vengono valutati 11 marker, con una soglia di 2 o più per la classificazione:
| Marker | Segnale | Condizione |
|---|---|---|
| webdriver | s300 | = "true" |
| flavor del vendor mancanti | s28 | Nessun oggetto chrome/safari su window |
| CDP headless chrome | s305 | headlessChrome = true |
| notifica negata | s88 | Notification.permission = "denied" alla prima visita |
| chrome senza runtime | s89 | window.chrome esiste ma chrome.runtime è assente |
| lingua singola | s90 | navigator.languages.length <= 1 |
| schermo predefinito 800x600 | s5 | Risoluzione predefinita di Chrome headless |
| UA HeadlessChrome | UA | Lo User-Agent contiene "HeadlessChrome" |
| dimensioni esterne pari a zero | s97 | outerWidth = 0 e outerHeight = 0 |
| WebGL SwiftShader | s70 | Il renderer contiene "swiftshader" (GPU software) |
| WebGL llvmpipe | s70 | Il renderer contiene "llvmpipe" (GPU software) |
I good bot noti vengono riconosciuti tramite il pattern dello User-Agent. Ciascuno viene verificato tramite reverse DNS per prevenire la falsificazione:
.googlebot.com)| Bot | Domini consentiti |
|---|---|
.googlebot.com, .google.com | |
| Bing | .search.msn.com |
| Apple | .applebot.apple.com |
| Yahoo | .crawl.yahoo.net |
| Yandex | .yandex.com, .yandex.net, .yandex.ru |
| DuckDuckGo | .duckduckgo.com |
Se una richiesta dichiara di essere Googlebot ma il reverse DNS del suo IP risolve a un dominio estraneo (una discrepanza PTR confermata, non semplicemente un lookup mancante/scaduto), viene classificata come bot (tipo spoofed:google).
Rilevamento basato sulla frequenza con punteggio di entropia:
| Frequenza (req/min) | Soglia di entropia | Azione |
|---|---|---|
| 120+ | < 0.1 | bot (tipo: rateBot) |
| 60-120 | < 0.3 | bot (tipo: rateBot) |
| 45-60 | < 0.1 | bot (tipo: rateBot) |
| < 45 | Qualsiasi | Normale |
Regola aggiuntiva: l'assenza di eventi mouse/tastiera dopo oltre 30 secondi di durata della sessione classifica la visita come bot con tipo noInteraction.
eval.toString().length produce valori coerenti per ciascun engine:
Qualsiasi altro valore indica che la funzione eval è stata agganciata da un framework di automazione, classificando la visita come bot con tipo unknown.
L'SDK client espone un booleano di comodità, result.bot.detected:
const result = await tracio.getResult()
if (result.bot.detected) { // Registra e blocca console.warn(`Bot detected (confidence ${result.bot.confidence})`) showCaptcha() return}
// Procedi con il loginawait login(credentials)Sul proprio server, agire sulla consegna del webhook. Il rilevamento dei bot
risiede nell'oggetto bot — bot.result e bot.type:
// `event` è il corpo della consegna del webhook (/docs/webhooks)app.post("/webhook/tracio", async (req, res) => { const event = req.body
if (event.bot.result === "bot") { await db.blockedRequests.insert({ visitorId: event.visitorId, botType: event.bot.type, ip: event.ip, timestamp: new Date(), }) }
res.status(200).send("OK")})Il rilevamento dei bot di TRACIO è progettato per falsi positivi quasi nulli. Tuttavia, possono verificarsi casi limite:
| Scenario | Rischio | Mitigazione |
|---|---|---|
Estensioni del browser che modificano navigator | Basso | La cross-validazione di più segnali previene attivazioni da singolo segnale |
| Software di sicurezza aziendale | Molto basso | Il rilevamento headless richiede 2 o più marker |
| Strumenti di accessibilità | Nessuno | Le API di accessibilità non attivano alcun segnale di rilevamento |
| Utenti VPN/proxy | Nessuno | L'uso della VPN è tracciato separatamente dal rilevamento dei bot |
In caso di falsi positivi, esaminare il campo bot.type per capire quale rilevatore è stato attivato e adeguare di conseguenza la propria policy.