翻譯前言:作為資料採集工程師經常和反爬蟲技術做鬥爭,其中我使用的爬蟲結構是:分散式+多機器+adsl | tor+phantomjs無介面瀏覽器+機器學習驗證碼破解/這樣的結構已經基本屬於爬蟲界的大招。但是對方如果通過檢測 phantomjs 的瀏覽器特性還是能區別出爬蟲。於是翻譯本文知己知彼,翻譯功底不好切勿見怪,高手請移步文尾部可以看英語原文。
這些天,許多web安全事故涉及自動化。 Web-scraping、密碼重用和點選欺詐攻擊對手試圖模擬真實使用者,從而將請求看起來像是來自一個瀏覽器。作為網站的所有者,你想確保你的web是為人類服務。假設你有基本的檢查cURL-like訪客的能力,下一個合理的步驟是確保訪客使用的是真正的ui驅動瀏覽器——而不是無頭瀏覽器 PhantomJS 和 SlimerJS 。在本文中,我們將展示一些PhantomJS檢測的技術。 我們決定專注於PhantomJS因為它是最受歡迎的無頭瀏覽器環境,但許多的概念,我們將討論適用於SlimerJS和其他工具。
目錄:
- HTTP棧
- 客戶端User-Agent
- 使用外掛
- 定時
- 全域性屬性
- 缺乏JavaScript引擎的功能
- 堆疊跟蹤
1: 檢查HTTP棧
首先:它可以檢測PhantomJS甚至在不用相應他(在獲取請求頭就可以檢測他)嗎?
如你所知,PhantomJS是建立在 Qt框架 。 Qt實現HTTP棧的方式使它突出於其他現代瀏覽器。
首先,讓我們看看Chrome,發出以下head:
1 2 3 4 5 6 7 |
GET / HTTP/1.1 Host: localhost:1337 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8,ru;q=0.6 |
然而在PhantomJS,相同的HTTP請求是這樣的:
1 2 3 4 5 6 7 |
GET / HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.8 Safari/534.34 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Connection: Keep-Alive Accept-Encoding: gzip Accept-Language: en-US,* Host: localhost:1337 |
你會注意到PhantomJS頭是不同於Chrome(事實證明,其他所有現代瀏覽器)有一些微妙的不同:
主機(host)
出現最後一行連線
頭(Connection)是大小寫混合- 唯一的
接受編碼
值是gzip - User-Agent
在伺服器上檢查這些HTTP頭的變化,它應該可以識別PhantomJS瀏覽器。
但是,相信這些值安全嗎? 如果敵人使用一個代理修改標題前面的無頭瀏覽器,他們可以修改這些標題顯得象一個正常的現代瀏覽器。
看來解決這個問題純粹只是在伺服器上不是合適的。 讓我們看看能做些什麼在客戶端,現在使用PhantomJS的JavaScript環境。
2: 客戶端User-Agent
檢查
我們可能無法通過HTTP信任User-Agent 的
值但是在客戶端呢?
1 2 3 |
if (/PhantomJS/.test(window.navigator.userAgent)) { console.log("PhantomJS environment detected."); } |
不幸的是,它同樣是可以被改變User-Agen和head 在PhantomJS 中檢測userAgent值,這可能是不夠的。
3: 使用外掛
navigator.plugins
包含一個陣列的外掛在瀏覽器內。 典型的外掛的價值觀包括Flash,ActiveX,支援Java applet,“ 預設瀏覽器助手 ”,這是一個外掛,表明這個瀏覽器是OS x的預設瀏覽器是否在我們的研究中,大多數新安裝的常見的瀏覽器包括至少一個預設外掛。
這是與PhantomJS,不實現任何外掛,也不提供一種方法來新增一個(使用 PhantomJS API )。
以下檢查可能會是有用的:
1 2 3 4 5 |
if (!(navigator.plugins instanceof PluginArray) || navigator.plugins.length == 0) { console.log("PhantomJS environment detected."); } else { console.log("PhantomJS environment not detected."); } |
另一方面,惡搞這個外掛很簡單陣列通過修改PhantomJS JavaScript環境 在頁面載入之前 。
也不難想象一個自定義構建的PhantomJS真實,實現外掛。 這比聽起來要容易得多,因為Qt PhantomJS構建提供了一個框架 本機API 實現外掛。
4: 定時
另一個感興趣的點是如何PhantomJS抑制JavaScript對話方塊:
1 2 3 4 5 6 7 8 |
var start = Date.now(); alert('Press OK'); var elapse = Date.now() - start; if (elapse < 15) { console.log("PhantomJS environment detected. #1"); } else { console.log("PhantomJS environment not detected."); } |
多次測量後,似乎如果警告對話方塊被限制了在15毫秒,瀏覽器可能不是被一個真實的人控制。 但使用這種方法意味著困擾真實使用者與一個警告他們會手動關閉。
5: 全域性屬性
PhantomJS 1。 x暴露在全域性物件兩個屬性:
1 2 3 4 5 |
if (window.callPhantom || window._phantom) { console.log("PhantomJS environment detected."); } else { console.log("PhantomJS environment not detected."); } |
然而,這些屬性的一部分 實驗功能 和在未來可能會改變。
6: 缺乏JavaScript引擎的功能
PhantomJS 1. x和2. x目前使用過時的WebKit引擎,這意味著有瀏覽器特性中存在的新瀏覽器PhantomJS並不存在。 這延伸到JavaScript引擎——即一些本機屬性和方法是不同的或在PhantomJS缺席。其中一個方法是Function.prototype。 繫結,PhantomJS 下面的示例檢查是否存在繫結,它沒有被欺騙的執行環境。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
(function () { if (!Function.prototype.bind) { console.log("PhantomJS environment detected. #1"); return; } if (Function.prototype.bind.toString().replace(/bind/g, 'Error') != Error.toString()) { console.log("PhantomJS environment detected. #2"); return; } if (Function.prototype.toString.toString().replace(/toString/g, 'Error') != Error.toString()) { console.log("PhantomJS environment detected. #3"); return; } console.log("PhantomJS environment not detected."); })(); |
這段程式碼是有點太棘手的詳細解釋,但你可以找到更多 我們的演示 。
7: 堆疊跟蹤
錯誤丟擲的JavaScript程式碼由PhantomJS通過評估 評估 命令包含一個堆疊跟蹤的唯一標識,我們可以確定無頭瀏覽器。
例如,假設PhantomJS評估以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 |
var err; try { null[0](); } catch (e) { err = e; } if (indexOfString(err.stack, 'phantomjs') > -1) { console.log("PhantomJS environment detected."); } else { console.log("PhantomJS environment is not detected."); } |
注意,這個示例使用一個定製的 indexOfString()
函式,留給讀者作為練習,因為本機String.prototype.indexOf
可以欺騙PhantomJS總是返回一個負面的結果。
現在,你如何讓PhantomJS指令碼執行這段程式碼? 技術之一是覆蓋一些經常使用DOM API函式可能被稱為。 例如,下面的程式碼覆蓋 document.querySelectorAll
檢查瀏覽器的堆疊跟蹤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var html = document.querySelectorAll('html'); var oldQSA = document.querySelectorAll; Document.prototype.querySelectorAll = Element.prototype.querySelectorAll = function () { var err; try { null[0](); } catch (e) { err = e; } if (indexOfString(err.stack, 'phantomjs') > -1) { return html; } else { return oldQSA.apply(this, arguments); } }; |
總結
在本文中,我們研究了7個不同的技術來識別PhantomJS,都在伺服器上,執行程式碼PhantomJS的客戶端JavaScript環境。 結合檢測結果與一個強大的反饋機制——例如,呈現動態頁面惰性或無效當前會話cookie——你可以獲得一個堅實的阻止PhantomJS訪客的防火牆。 然而,總是記住這些技術並不可靠,和一個複雜的對手最終將獲得通過。
為了瞭解更多,我們建議看的記錄 從2014年美國AppSec我們的演示 ( 幻燈片 )。 我們也放在一起 GitHub庫 實現示例和可能的危害,本文提供的技術。
感謝你的閱讀,快樂狩獵。
貢獻者:
- 連結分享:
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!