System wykrywania botów TRACIO identyfikuje zautomatyzowane przeglądarki, narzędzia headless i ataki skryptowe przy użyciu dwuwarstwowej architektury: zbierania sygnałów po stronie klienta oraz analizy po stronie serwera. Wykrywa popularne frameworki automatyzacji, przeglądarki headless, agentów AI przeglądających sieć oraz przeglądarki antidetect z niemal zerową liczbą fałszywych alarmów, jednocześnie automatycznie dodając legalne crawlery wyszukiwarek do listy dozwolonych.
Agent przeglądarki zbiera szereg sygnałów specyficznych dla botów oraz sygnałów walidacji krzyżowej, które zasilają decyzje po stronie serwera. Poniższe identyfikatory sygnałów mają charakter poglądowy — wewnętrzne identyfikatory nie stanowią stabilnego publicznego kontraktu:
| Signal | Opis |
|---|---|
s300 (webdriver) | Flaga navigator.webdriver — ustawiana na true przez frameworki automatyzacji |
s301 (eval length) | eval.toString().length — Chrome/Edge: 33, Firefox: 37. Inne wartości wskazują na instrumentację. |
s305 (bot composite) | Przeszukuje window/document w poszukiwaniu 14 artefaktów frameworków automatyzacji |
s97 (headless markers) | Artefakty CDP, uprawnienia do powiadomień, liczba wtyczek, wymiary zewnętrzne |
s157 (automation scan) | Kompleksowy skan pod kątem Selenium, Puppeteer, PhantomJS, Playwright i 10 innych |
s158 (iframe webdriver) | Tworzy ukryty iframe i odczytuje w nim navigator.webdriver. Wykrywa narzędzia, które łatają główną ramkę, ale zapominają o iframe'ach. |
s159 (native function) | Usuwa Function i Object oraz testuje, czy gettery są rzeczywiście natywne. Wykrywa instrumentację opartą na Proxy. |
s155 (window CRC32) | Skan hasha CRC32 każdej właściwości window w celu wykrycia wstrzykniętych globalnych obiektów automatyzacji |
s163 (devtools trap) | Pułapka na getter konsoli — wykrywa, gdy DevTools są aktywnie otwarte |
Serwer uruchamia zestaw detektorów, których ważone wyniki łączą się w
wynik botowy (bot score). Wynik jest mapowany na werdykt poprzez progi — bot, gdy
wynosi ≥ 0,70, suspicious, gdy ≥ 0,30, w przeciwnym razie human — a sygnał
typu hard-fail (taki jak navigator.webdriver) wymusza werdykt bot bez
warunków. Werdykty bot niosą ze sobą swobodną etykietę bot_type.
Reprezentatywne detektory i ich efekt:
| Detektor | Efekt |
|---|---|
| Flaga webdriver | Hard-fail → bot (typ webdriver) |
| Złożony skan automatyzacji / frameworków | Wysoka waga → bot (typ {framework}) |
| Markery headless | Ważone → bot (typ headless) |
| Anomalia eval-length | Ważone → bot (typ unknown) |
| Wzorzec UA złego bota | Ważone → bot (typ {label}) |
| Zweryfikowany dobry bot (reverse DNS) | Lista dozwolonych → human |
| Behawioralne (tempo / entropia / interakcja) | Ważone → bot (typ rateBot) |
| VM (Enterprise) · Emulator · DevTools (Business+) | Ważone sygnały urządzenia/manipulacji |
Plan i dostępność. Wykrywanie DevTools działa w planach Business i Enterprise; wykrywanie VM to Enterprise; wykrywanie emulatora działa we wszystkich planach. Wszystko to działa w agencie webowym. Wykrywanie roota, jailbreaka, sklonowanych/zdublowanych aplikacji, Fridy oraz przywrócenia ustawień fabrycznych zależy od natywnych sygnałów mobilnych i nie jest skuteczne we wdrożeniu wyłącznie webowym (w fazie rozwoju). Polegaj na werdyktach dotyczących automatyzacji, headless, agentów AI, antidetect, VM/emulatora i zachowania, które w środowisku webowym są w pełni aktywne.
Wykrywanie botów zapisuje pole bot_result w każdym zdarzeniu (oraz bot.result w
payloadzie webhooka).
bot_result przyjmuje jedną z trzech kanonicznych wartości:
| Wynik | Opis |
|---|---|
human | Nie znaleziono wskaźników automatyzacji. Zweryfikowane crawlery wyszukiwarek również dają wynik human. |
bot | Wykryto dostęp zautomatyzowany lub skryptowy. Towarzyszy mu swobodna etykieta bot_type. |
uncertain | Mieszane lub słabe sygnały — ani wyraźnie ludzki, ani wyraźnie zautomatyzowany. |
Jest to mapowane na biznesowe pole decision (real, fake lub suspicious)
używane w całym dashboardzie oraz na bot.result w
payloadzie webhooka.
"bot")bot_type to swobodny ciąg znaków. Poniższe wartości to poglądowe przykłady tego,
co emitują detektory, a nie wyczerpujący enum:
| Typ | Metoda wykrywania |
|---|---|
webdriver | navigator.webdriver jest true |
selenium | Wykryto właściwości window/document specyficzne dla Selenium |
puppeteer | Dopasowano wskaźniki headless Puppeteer/Chromium |
playwright | Wykryto markery specyficzne dla Playwright lub ciąg UA |
headless | Wyzwolono 2+ z 11 markerów headless |
phantomjs | Wykryto globalne obiekty PhantomJS (callPhantom, _phantom) |
nightmare | Wykryto globalne obiekty NightmareJS |
unknown | Anomalia eval-length lub inne niespecyficzne wskaźniki automatyzacji |
rateBot | Analiza tempa zachowań przekroczyła progi |
Najbardziej bezpośrednie wykrywanie. Wszystkie główne frameworki automatyzacji ustawiają navigator.webdriver = true zgodnie ze specyfikacją WebDriver. Jest to sprawdzane zarówno w głównej ramce (s300), jak i w ukrytym iframe (s158), aby wykryć narzędzia, które łatają jedynie główną ramkę.
Kompleksowe skanowanie właściwości window i document w poszukiwaniu artefaktów specyficznych dla frameworków:
| Framework | Wykrywane właściwości |
|---|---|
| Selenium | _Selenium_IDE_Recorder, _selenium, calledSelenium, __selenium_evaluate, $cdc_* (ChromeDriver) |
| Puppeteer | domAutomation, domAutomationController, UA HeadlessChrome |
| Playwright | __playwright, flaga automation-controlled |
| PhantomJS | callPhantom, _phantom |
| NightmareJS | __nightmare, nightmare |
| CefSharp | CefSharp |
| Awesomium | awesomium |
| WebDriverIO | wdioElectron |
| Cypress | Właściwość window __cypress |
Skan wykorzystuje również wzorzec regex /^([a-z]){3}_.*_(Array|Promise|Symbol)$/ do wykrywania wstrzykniętych przez Selenium pomocniczych globalnych obiektów.
Oceniane jest 11 markerów, z progiem 2 lub więcej dla klasyfikacji:
| Marker | Sygnał | Warunek |
|---|---|---|
| webdriver | s300 | = "true" |
| brak odmian vendor | s28 | Brak obiektów chrome/safari na window |
| CDP headless chrome | s305 | headlessChrome = true |
| notification denied | s88 | Notification.permission = "denied" przy pierwszej wizycie |
| chrome no runtime | s89 | window.chrome istnieje, ale brakuje chrome.runtime |
| pojedynczy język | s90 | navigator.languages.length <= 1 |
| domyślny ekran 800x600 | s5 | Domyślna rozdzielczość headless Chrome |
| UA HeadlessChrome | UA | User-Agent zawiera "HeadlessChrome" |
| zerowe wymiary zewnętrzne | s97 | outerWidth = 0 i outerHeight = 0 |
| WebGL SwiftShader | s70 | Renderer zawiera "swiftshader" (programowy GPU) |
| WebGL llvmpipe | s70 | Renderer zawiera "llvmpipe" (programowy GPU) |
Znane dobre boty są rozpoznawane po wzorcu User-Agent. Każdy jest weryfikowany poprzez reverse DNS, aby zapobiec spoofingowi:
.googlebot.com)| Bot | Dozwolone domeny |
|---|---|
.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 |
Jeśli żądanie podaje się za Googlebot, ale reverse DNS jego IP rozwiązuje się na obcą domenę (potwierdzona niezgodność PTR, a nie jedynie brakujące/przeterminowane zapytanie), jest klasyfikowane jako bot (typ spoofed:google).
Wykrywanie oparte na tempie z punktacją entropii:
| Tempo (żąd./min) | Próg entropii | Akcja |
|---|---|---|
| 120+ | < 0.1 | bot (typ: rateBot) |
| 60-120 | < 0.3 | bot (typ: rateBot) |
| 45-60 | < 0.1 | bot (typ: rateBot) |
| < 45 | Dowolna | Normalne |
Dodatkowa reguła: brak zdarzeń myszy/klawiatury po 30+ sekundach czasu trwania sesji klasyfikuje wizytę jako bot z typem noInteraction.
eval.toString().length daje spójne wartości w zależności od silnika:
Każda inna wartość wskazuje, że funkcja eval została podpięta (hooked) przez framework automatyzacji, co klasyfikuje wizytę jako bot z typem unknown.
Klienckie SDK udostępnia wygodną wartość logiczną, 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)Na swoim serwerze reaguj na dostarczenie webhooka. Wykrywanie botów
znajduje się w obiekcie bot — bot.result i 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")})Wykrywanie botów TRACIO zostało zaprojektowane z myślą o niemal zerowej liczbie fałszywych alarmów. Mogą jednak wystąpić przypadki brzegowe:
| Scenariusz | Ryzyko | Środek zaradczy |
|---|---|---|
Rozszerzenia przeglądarki modyfikujące navigator | Niskie | Wielokrotna walidacja krzyżowa sygnałów zapobiega wyzwoleniu przez pojedynczy sygnał |
| Korporacyjne oprogramowanie zabezpieczające | Bardzo niskie | Wykrywanie headless wymaga 2+ markerów |
| Narzędzia dostępności | Brak | API dostępności nie wyzwalają żadnych sygnałów wykrywania |
| Użytkownicy VPN/proxy | Brak | Korzystanie z VPN jest śledzone oddzielnie od wykrywania botów |
Jeśli napotkasz fałszywe alarmy, sprawdź pole bot.type, aby zrozumieć, który detektor został wyzwolony, i odpowiednio dostosuj swoją politykę.