Puppeteer Tespiti Gerçekte Nasıl Çalışır: Botları Ele Veren 12 Sinyal
Otomasyon çerçeveleri gerçek bir tarayıcının parmak izini devralır ama onu düzinelerce gözlemlenebilir şekilde değiştirir. Puppeteer ve Playwright'ı yakalamak için kullanılan 12 JavaScript, ağ ve davranış sinyaline dair saha rehberi.
Otomasyon çerçeveleri gerçek tarayıcıları kontrol eder, bu da tarayıcının parmak izini devraldıkları anlamına gelir. Puppeteer tarafından sürülen bir Chrome, bir insanın Chrome'uyla aynı user agent'a, aynı Chrome sürümüne ve aynı Chromium derlemesine sahiptir. Yüzeysel olarak birebir aynı görünürler.
Ama otomasyon çerçeveleri tarayıcıyı düzinelerce ince şekilde değiştirir — çoğu JavaScript'ten gözlemlenebilir. Tespit sihir değildir. Bir kontrol listesidir.
1. navigator.webdriver bayrağı
En basit ve en ünlü sinyal. Chrome bir otomasyon çerçevesi altında çalıştığında, navigator.webdriver true döndürür. Bu, W3C WebDriver spesifikasyonunun bir parçasıdır ve Chromium onu varsayılan olarak uygular.
Her ciddi otomasyon projesi bunu saniyeler içinde yamalar. Puppeteer-extra-stealth getter'ı ezer. Playwright kullanıcıları yeni belgelere Object.defineProperty betikleri enjekte eder. Bayrağı gizlemek çok kolaydır.
Ama bunun çok kolay gizlenebilmesi başlı başına bir sinyaldir. Meşru bir Chrome'un hiçbir şeyi gizlemesine gerek yoktur. Bir sayfa Object.getOwnPropertyDescriptor(Navigator.prototype, 'webdriver') kontrolü yaptığında ve tanımlayıcı yerel bir tarayıcınınkinden farklı göründüğünde — bayrak yamalandıktan sonra bile otomasyon yakalanır.
2. chrome nesnesi anomalisi
Meşru Chrome, önemli bir yapıya sahip global bir window.chrome nesnesi sunar — chrome.runtime, chrome.loadTimes, chrome.csi. Headless Chrome ve eski Puppeteer kurulumları ya bu nesneyi tamamen atlar ya da soyulmuş bir sürümünü sunar.
Stealth eklentiler nesneyi yeniden oluşturur, ama bu yeniden oluşturma kusurludur. chrome.runtime.onConnect chrome.runtime.PlatformOs olmadan mevcut olabilir. Fonksiyon imzaları undefined yerine nesne döndürebilir. Her uyumsuzluk pozitif bir sinyaldir.
3. Permissions API tutarsızlıkları
Gerçek tarayıcılar Permissions API üzerinden sorgulandığında tutarlı sonuçlar döndürür. Kullanıcı açıkça izin vermediyse ya da reddetmediyse navigator.permissions.query({name: 'notifications'}) 'default' döndürmelidir.
Headless Chrome varsayılan olarak 'denied' döndürür, çünkü izin istemi gösterecek bir arayüz yoktur. Otomasyon çerçeveleri bunu yamalar — ama çoğu zaman yanlış. Yaygın bir ipucu: 'clipboard-read' gibi olağan dışı bir izni sorgulamak, gerçek Chrome'un mevcut sürümde yaptığıyla eşleşmeyen bir sonuç döndürür.
4. Eklenti ve MIME tipi dizileri
Gerçek bir tarayıcıda navigator.plugins, PDF görüntüleyici ve Chromium PDF eklentisi gibi girdilere sahip bir PluginArray döndürür. Headless modda bu dizi boştur.
Stealth eklentiler sahte girdiler ekler, ama girdilerin sık sık yanlış özellikleri olur — eksik length, yanlış açıklama alanları ya da instanceof ile test edildiğinde Plugin örnekleri gibi davranmayan eklenti nesneleri.
5. Dil ve yerel ayar uyumsuzlukları
navigator.language ve navigator.languages, Accept-Language HTTP başlığıyla eşleşmelidir. Ayrıca Intl.DateTimeFormat().resolvedOptions().timeZone tarafından bildirilen saat dilimiyle de tutarlı olmalıdır.
Kiev'de (Europe/Kyiv saat dilimi) olduğunu iddia eden ama Accept-Language: en-US,en;q=0.9 gönderen ve navigator.language === 'en-US' bildiren bir bot mümkündür ama istatistiksel olarak alışılmadıktır. Frankfurt'taki bir veri merkezinden gelen bir IP ile birleştiğinde tablo netleşir.
6. WebGL renderer dizileri
WebGL2RenderingContext.getParameter(WebGLDebugRendererInfo.UNMASKED_RENDERER_WEBGL) GPU üreticisini ve modelini döndürür. Gerçek bir makinede bu şöyle olabilir:
ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0)
Bir konteynerde çalışan headless Chrome sıklıkla şunu döndürür:
ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero)), SwiftShader driver)
SwiftShader veya Subzero içeren herhangi bir GPU dizisi güçlü bir bot sinyalidir.
7. Ekran ve görüntüleme alanı anomalileri
Gerçek bir tarayıcı penceresinin, tarayıcı çerçevesini — adres çubuğu, sekmeler, yer imleri çubuğu — hesaba katan window.outerWidth ve window.outerHeight değeri vardır. Dış ve iç boyutlar arasındaki fark dikey olarak tipik olarak 80–140 pikseldir.
Headless tarayıcılarda çoğu zaman outerHeight === innerHeight olur çünkü görüntülenecek bir çerçeve yoktur. headless: false ile çalışan Puppeteer bunu düzeltir, ama birçok otomasyon kurulumu hâlâ eşit boyutlarla çalışır.
8. Yazı tipi numaralandırması
Gerçek kullanıcıların işletim sistemine, diline ve yüklü uygulamalara göre değişen yüzlerce yüklü yazı tipi vardır. Office yüklü Windows 11'de 500'den fazla yazı tipi bulunur. Alpine Linux çalıştıran otomasyon konteynerlerinde 30 tane vardır.
document.fonts.check() ya da ekran dışı canvas oluşturma yoluyla yapılan yazı tipi numaralandırması bunu anında ortaya çıkarır. Kendini Windows 11 Chrome olarak bildiren ama yalnızca 30 yazı tipi sunan bir tarayıcı neredeyse kesinlikle otomasyondur.
9. Fare hareketi entropisi
Gerçek kullanıcılar fareyi titremeyle hareket ettirir. Eğriler doğrusal değildir. Hız değişir. İki tıklama arasında tipik olarak yüzlerce mousemove olayı vardır.
Otomasyon çerçeveleri hareketi sentezler — ya koordinatlara düz çizgilerle ya da bir insan elinin mikro titremelerinden yoksun programlanmış eğrilerle. Bezier eğrisi simülasyonları bile şüpheli derecede pürüzsüz ivmelenme profillerine sahip olma eğilimindedir.
Bot tespit sistemleri hareket izlerini toplar ve bunları bir insan hareketi modeline göre puanlar. Fazla tutarlı hız, fazla temiz eğriler ya da eksik mikro olaylar içeren izler işaretlenir.
10. Zamanlama imzaları
Otomasyon çerçeveleri JavaScript'i kullanıcı tarafından sürülen tarayıcılardan farklı zamanlama özellikleriyle yürütür. Olaylar arasındaki, özellikle pointerdown ve pointerup arasındaki performance.now() zamanlaması farklı bir dağılım izler.
Gerçek tıklama basılı tutma süreleri yüksek varyansla 50–150 ms arasındadır. Puppeteer'ın varsayılan tıklama basılı tutma süresi sabit bir değerdir — genellikle 30 ms ya da 100 ms — neredeyse hiç varyans olmadan. Aynı basılı tutma sürelerine sahip yüz tıklama kesin bir otomasyon göstergesidir.
11. TLS parmak izi uyumsuzluğu
Bu, JavaScript'i tamamen atlatır. Puppeteer bağlandığında Chromium'un TLS yığınını kullanır — gerçek bir Chrome ile aynı. Ama user agent taklidi yoluyla Chrome gibi davranan undici tabanlı ya da axios tabanlı scraper'lar, belirgin şekilde farklı bir Client Hello imzasına (JA4 hash'i) sahip olan Node.js'in TLS yığınını kullanır.
User-Agent: Chrome/124.0.6367.60 iddia eden ama bir Node.js TLS parmak izi sunan bir istek, tarayıcı olmayan bir istemcinin anında doğrulanmasıdır.
12. CDP protokolü sızıntısı
Puppeteer ve Playwright, Chrome ile Chrome DevTools Protocol üzerinden iletişim kurar. Bazı yapılandırmalarda bu protokol tespit edilebilir izler bırakır — Runtime nesnesinde ekstra özellikler, değiştirilmiş Error.stack biçimleri ya da yalnızca bir CDP istemcisi ekliyken beliren belirli console.debug çıktıları.
Özellikle Runtime.enable komutu, yığın izlerinin nasıl işlendiğini değiştirir. Asla hataya yol açmayan botlar bu sinyalden kaçınır, ama bir istisnaya çarpan herhangi bir otomasyon akışı (ki çoğu çarpar) parmak izi bırakır.
Bu sinyalleri katmanlamak
Hiçbir tek sinyal otomasyonun kanıtı değildir. Olağan dışı bir GPU sürücüsüne sahip gerçek bir kullanıcı garip bir WebGL dizisi döndürebilir. Gizliliğe önem veren bir kullanıcı navigator.plugins'i değiştirmiş olabilir.
Modern tespitin gücü sinyalleri birleştirmekten gelir — 12 zayıf pozitif tek bir güçlü pozitiften daha güçlüdür, çünkü gerçek bir kullanıcı aynı anda nadiren 2–3'ten fazla anomaliyi tetikler.
Tespit sistemleri her sinyale bir ağırlık atar ve bir puan hesaplar. Eşiğin üzerinde, ziyaretçi otomasyon olarak ele alınır. Tam eşik ve ağırlıklar doğru ayarlanması en zor kısımlardır — çok katı olursa meşru kullanıcılar engellenir; çok esnek olursa gelişmiş botlar sızar.
Sinyallerin kendisi kolay kısımdır. Neredeyse her otomasyon çerçevesi 12'sini de sızdırır. Asıl mühendislik, hangi kombinasyonların önemli olduğuna, hangilerinin yanlış pozitif olduğuna ve otomasyon çerçeveleri uyum sağladıkça modelin nasıl güncelleneceğine karar vermektir.