Das Bot-Erkennungssystem von TRACIO identifiziert automatisierte Browser, Headless-Tools und skriptbasierte Angriffe mithilfe einer zweischichtigen Architektur: clientseitige Signalerfassung und serverseitige Analyse. Es erkennt gängige Automatisierungs-Frameworks, Headless-Browser, KI-Browsing-Agenten und Anti-Detect-Browser mit nahezu null Falsch-Positiven und setzt legitime Suchmaschinen-Crawler automatisch auf die Allowlist.
Der Browser-Agent erfasst eine Reihe von bot-spezifischen und Cross-Validation-Signalen, die in die serverseitigen Entscheidungen einfließen. Die untenstehenden Signal-IDs sind illustrativ — die internen IDs sind kein stabiler öffentlicher Vertrag:
| Signal | Beschreibung |
|---|---|
s300 (webdriver) | navigator.webdriver-Flag — von Automatisierungs-Frameworks auf true gesetzt |
s301 (eval length) | eval.toString().length — Chrome/Edge: 33, Firefox: 37. Andere Werte deuten auf Instrumentierung hin. |
s305 (bot composite) | Durchsucht window/document nach 14 Automatisierungs-Framework-Artefakten |
s97 (headless markers) | CDP-Artefakte, Benachrichtigungsberechtigungen, Plugin-Anzahl, Außenabmessungen |
s157 (automation scan) | Umfassender Scan nach Selenium, Puppeteer, PhantomJS, Playwright und 10 weiteren |
s158 (iframe webdriver) | Erstellt einen versteckten iframe und liest darin navigator.webdriver. Erfasst Tools, die den Hauptframe patchen, aber iframes vergessen. |
s159 (native function) | Löscht Function und Object und testet, ob Getter wirklich nativ sind. Erkennt Proxy-basierte Instrumentierung. |
s155 (window CRC32) | CRC32-Hash-Scan jeder window-Eigenschaft zur Erkennung injizierter Automatisierungs-Globals |
s163 (devtools trap) | Console-Getter-Falle — erkennt, wenn DevTools aktiv geöffnet sind |
Der Server führt eine Reihe von Detektoren aus, deren gewichtete Ausgaben zu
einem Bot-Score kombiniert werden. Der Score wird über Schwellenwerte einem
Verdikt zugeordnet — bot, wenn er ≥ 0,70 ist,
suspicious, wenn ≥ 0,30, andernfalls human — und ein Hard-Fail-Signal (etwa
navigator.webdriver) erzwingt unmittelbar ein bot-Verdikt. Bot-Verdikte tragen
ein freies bot_type-Label.
Repräsentative Detektoren und ihre Wirkung:
| Detektor | Wirkung |
|---|---|
| Webdriver-Flag | Hard-Fail → bot (Typ webdriver) |
| Composite-Automatisierungs-/Framework-Scan | Hohes Gewicht → bot (Typ {framework}) |
| Headless-Marker | Gewichtet → bot (Typ headless) |
| Eval-Length-Anomalie | Gewichtet → bot (Typ unknown) |
| Bad-Bot-UA-Muster | Gewichtet → bot (Typ {label}) |
| Verifizierter guter Bot (Reverse DNS) | Allowlist → human |
| Verhaltensbasiert (Rate / Entropie / Interaktion) | Gewichtet → bot (Typ rateBot) |
| VM (Enterprise) · Emulator · DevTools (Business+) | Gewichtete Geräte-/Tamper-Signale |
Tarif & Verfügbarkeit. Die DevTools-Erkennung läuft auf Business und Enterprise; die VM-Erkennung ist Enterprise; die Emulator-Erkennung läuft in allen Tarifen. All dies funktioniert im Web-Agenten. Die Erkennung von Root, Jailbreak, geklonten/dualen Apps, Frida und Werksreset hängt von nativen Mobile-Signalen ab und ist in der reinen Web-Bereitstellung nicht wirksam (in Entwicklung). Verlassen Sie sich auf die Verdikte zu Automatisierung, Headless, KI-Agenten, Anti-Detect, VM/Emulator und Verhalten, die auf Web vollständig aktiv sind.
Die Bot-Erkennung schreibt bei jedem Ereignis ein bot_result-Feld (und bot.result im
Webhook-Payload).
bot_result ist einer von drei kanonischen Werten:
| Ergebnis | Beschreibung |
|---|---|
human | Keine Automatisierungsindikatoren gefunden. Verifizierte Suchmaschinen-Crawler ergeben ebenfalls human. |
bot | Automatisierter oder skriptbasierter Zugriff erkannt. Ein freies bot_type-Label begleitet es. |
uncertain | Gemischte oder schwache Signale — weder eindeutig menschlich noch eindeutig automatisiert. |
Dies wird dem geschäftlichen decision-Feld (real, fake oder suspicious)
zugeordnet, das im gesamten Dashboard verwendet wird, sowie bot.result im
Webhook-Payload.
"bot" ist)bot_type ist ein freier String. Die untenstehenden Werte sind illustrative Beispiele dafür,
was die Detektoren ausgeben, kein vollständiges Enum:
| Typ | Erkennungsmethode |
|---|---|
webdriver | navigator.webdriver ist true |
selenium | Selenium-spezifische window/document-Eigenschaften erkannt |
puppeteer | Puppeteer-/Chromium-Headless-Indikatoren abgeglichen |
playwright | Playwright-spezifische Marker oder UA-String erkannt |
headless | 2+ von 11 Headless-Markern ausgelöst |
phantomjs | PhantomJS-Globals erkannt (callPhantom, _phantom) |
nightmare | NightmareJS-Globals erkannt |
unknown | Eval-Length-Anomalie oder andere unspezifische Automatisierungsindikatoren |
rateBot | Verhaltensbasierte Ratenanalyse hat Schwellenwerte überschritten |
Die direkteste Erkennung. Alle wichtigen Automatisierungs-Frameworks setzen navigator.webdriver = true gemäß der WebDriver-Spezifikation. Dies wird sowohl im Hauptframe (s300) als auch in einem versteckten iframe (s158) geprüft, um Tools zu erfassen, die nur den Hauptframe patchen.
Umfassendes Scannen von window- und document-Eigenschaften nach framework-spezifischen Artefakten:
| Framework | Erkannte Eigenschaften |
|---|---|
| Selenium | _Selenium_IDE_Recorder, _selenium, calledSelenium, __selenium_evaluate, $cdc_* (ChromeDriver) |
| Puppeteer | domAutomation, domAutomationController, HeadlessChrome-UA |
| Playwright | __playwright, automation-controlled-Flag |
| PhantomJS | callPhantom, _phantom |
| NightmareJS | __nightmare, nightmare |
| CefSharp | CefSharp |
| Awesomium | awesomium |
| WebDriverIO | wdioElectron |
| Cypress | __cypress-window-Eigenschaft |
Der Scan verwendet außerdem ein Regex-Muster /^([a-z]){3}_.*_(Array|Promise|Symbol)$/, um die von Selenium injizierten Helper-Globals zu erkennen.
11 Marker werden ausgewertet, mit einem Schwellenwert von 2 oder mehr für die Klassifizierung:
| Marker | Signal | Bedingung |
|---|---|---|
| webdriver | s300 | = "true" |
| fehlende Vendor-Flavors | s28 | Keine chrome-/safari-Objekte auf window |
| CDP Headless Chrome | s305 | headlessChrome = true |
| notification denied | s88 | Notification.permission = "denied" beim ersten Besuch |
| chrome no runtime | s89 | window.chrome existiert, aber chrome.runtime fehlt |
| einzelne Sprache | s90 | navigator.languages.length <= 1 |
| Standardbildschirm 800x600 | s5 | Standardauflösung von Headless Chrome |
| HeadlessChrome-UA | UA | User-Agent enthält "HeadlessChrome" |
| Außenabmessungen null | s97 | outerWidth = 0 und outerHeight = 0 |
| WebGL SwiftShader | s70 | Renderer enthält "swiftshader" (Software-GPU) |
| WebGL llvmpipe | s70 | Renderer enthält "llvmpipe" (Software-GPU) |
Bekannte gute Bots werden am User-Agent-Muster erkannt. Jeder wird über Reverse DNS verifiziert, um Spoofing zu verhindern:
.googlebot.com)| Bot | Erlaubte Domains |
|---|---|
.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 |
Wenn eine Anfrage vorgibt, Googlebot zu sein, das Reverse DNS ihrer IP aber auf eine fremde Domain auflöst (eine bestätigte PTR-Nichtübereinstimmung, nicht bloß ein fehlender/abgelaufener Lookup), wird sie als bot (Typ spoofed:google) klassifiziert.
Ratenbasierte Erkennung mit Entropie-Scoring:
| Rate (req/min) | Entropie-Schwellenwert | Aktion |
|---|---|---|
| 120+ | < 0.1 | bot (Typ: rateBot) |
| 60-120 | < 0.3 | bot (Typ: rateBot) |
| 45-60 | < 0.1 | bot (Typ: rateBot) |
| < 45 | Beliebig | Normal |
Zusätzliche Regel: Keine Maus-/Tastatur-Ereignisse nach 30+ Sekunden Sitzungsdauer klassifiziert den Besuch als bot mit Typ noInteraction.
eval.toString().length erzeugt je Engine konsistente Werte:
Jeder andere Wert deutet darauf hin, dass die eval-Funktion von einem Automatisierungs-Framework gehookt wurde, was den Besuch als bot mit Typ unknown klassifiziert.
Das Client-SDK stellt einen praktischen Boolean bereit, result.bot.detected:
const result = await tracio.getResult()
if (result.bot.detected) { // Log and block console.warn(`Bot detected (confidence ${result.bot.confidence})`) showCaptcha() return}
// Proceed with loginawait login(credentials)Reagieren Sie auf Ihrem Server auf die Webhook-Zustellung. Die Bot-Erkennung
befindet sich im bot-Objekt — bot.result und bot.type:
// `event` is the webhook delivery body (/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")})Die Bot-Erkennung von TRACIO ist auf nahezu null Falsch-Positive ausgelegt. Dennoch können Grenzfälle auftreten:
| Szenario | Risiko | Gegenmaßnahme |
|---|---|---|
Browser-Erweiterungen, die navigator verändern | Gering | Mehrfache Signal-Cross-Validation verhindert Auslösung durch ein einzelnes Signal |
| Unternehmens-Sicherheitssoftware | Sehr gering | Headless-Erkennung erfordert 2+ Marker |
| Barrierefreiheits-Tools | Keines | Barrierefreiheits-APIs lösen keine Erkennungssignale aus |
| VPN-/Proxy-Nutzer | Keines | VPN-Nutzung wird getrennt von der Bot-Erkennung verfolgt |
Wenn Sie auf Falsch-Positive stoßen, prüfen Sie das bot.type-Feld, um zu verstehen, welcher Detektor ausgelöst wurde, und passen Sie Ihre Richtlinie entsprechend an.