web-dev-qa-db-ja.com

SeleniumとChromedriverを同時に使用していることをWebサイトで検出できますか?

Chromedriverを使ってSeleniumをテストしていますが、自動化がまったく行われていなくても、Seleniumを使用していることを検出できるページがいくつかあることに気付きました。 SeleniumとXephyrを介してクロムを使用して手動でブラウズしているだけでも、疑わしい活動が検出されたというページが頻繁に表示されます。私は私のユーザーエージェントと私のブラウザの指紋をチェックしました、そしてそれらはすべて通常のクロムブラウザと全く同じです。

通常のクロムでこれらのサイトを閲覧すると、すべてうまくいくが、Seleniumを使用した瞬間に検出された。

理論的には、chromedriverとchromeは、どのWebサーバにとっても文字通りまったく同じに見えるはずですが、どういうわけか彼らはそれを検出することができます。

テストコードが欲しいなら、これを試してみてください。

from pyvirtualdisplay import Display
from Selenium import webdriver

display = Display(visible=1, size=(1600, 902))
display.start()
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument('--profile-directory=Default')
chrome_options.add_argument("--incognito")
chrome_options.add_argument("--disable-plugins-discovery");
chrome_options.add_argument("--start-maximized")
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.delete_all_cookies()
driver.set_window_size(800,800)
driver.set_window_position(0,0)
print 'arguments done'
driver.get('http://stubhub.com')

Stubhubをブラウズすると、1つか2つのリクエスト内でリダイレクトされて「ブロック」されます。私はこれを調査しています、そして、ユーザーがSeleniumを使用していることを彼らがどのように知ることができるかについて私は理解することができません。

どうやってやっているの?

更新を編集します。

私はFirefoxにSelenium IDEプラグインをインストールしましたが、通常のFirefoxブラウザでstubhub.comにアクセスすると、追加のプラグインだけで禁止されました。

編集:

送受信されているHTTPリクエストを表示するためにFiddlerを使用すると、 '偽のブラウザ'リクエストのレスポンスヘッダに 'no-cache'が含まれていることに気付きました。

編集:

このような結果 JavascriptのSelenium Webdriverページにいることを検出する方法はありますか Webドライバを使用していることを検出する方法はないはずです。しかし、この証拠はそうでないことを示唆しています。

編集:

サイトは彼らのサーバーに指紋をアップロードする、しかし私がチェックした、そしてSeleniumの指紋はクロムを使うとき指紋と同一である。

編集:

これは、サーバーに送信するフィンガープリントペイロードの1つです。

{"appName":"Netscape","platform":"Linuxx86_64","cookies":1,"syslang":"en-US","userlang":"en-US","cpu":"","productSub":"20030107","setTimeout":1,"setInterval":1,"plugins":{"0":"ChromePDFViewer","1":"ShockwaveFlash","2":"WidevineContentDecryptionModule","3":"NativeClient","4":"ChromePDFViewer"},"mimeTypes":{"0":"application/pdf","1":"ShockwaveFlashapplication/x-shockwave-flash","2":"FutureSplashPlayerapplication/futuresplash","3":"WidevineContentDecryptionModuleapplication/x-ppapi-widevine-cdm","4":"NativeClientExecutableapplication/x-nacl","5":"PortableNativeClientExecutableapplication/x-pnacl","6":"PortableDocumentFormatapplication/x-google-chrome-pdf"},"screen":{"width":1600,"height":900,"colorDepth":24},"fonts":{"0":"monospace","1":"DejaVuSerif","2":"Georgia","3":"DejaVuSans","4":"TrebuchetMS","5":"Verdana","6":"AndaleMono","7":"DejaVuSansMono","8":"LiberationMono","9":"NimbusMonoL","10":"CourierNew","11":"Courier"}}

Seleniumとchromeでは同じ

編集:

VPNは使い捨てですが、最初のページを読み込んだ後に検出されます。明らかにいくつかのJavaScriptがSeleniumを検出するために実行されています。

245
Ryan Weinstein

Macユーザーの場合

VimまたはPerlを使用してcdc_変数を置き換える

vimを使用するか、@ Vic Seedoubleyewが@ Erti-Chris Eelmaaによる回答で指摘したように、Perlを使用して、chromedriver(-のcdc_変数を置き換えることができます。 その変数の詳細については、@ Erti-Chris Eelmaaの投稿を参照)。 vimまたはPerlを使用すると、ソースコードを再コンパイルしたり、16進エディタを使用したりする必要がなくなります。編集する前に、元のchromedriverのコピーを作成してください。また、以下のメソッドはchromedriver version 2.41.578706でテストされました。


Vimを使用

vim /path/to/chromedriver

上記の行を実行すると、おそらく大量の意味不明な文字が表示されます。以下をせよ:

  1. cdc_と入力してreturnを押して、/cdc_を検索します。
  2. aを押して編集を有効にします。
  3. $cdc_lasutopfhvcZLmcflをすべて削除し、削除されたものを同じ量の文字に置き換えます。そうしないと、chromedriverは失敗します。
  4. 編集が完了したら、escを押します。
  5. 変更を保存して終了するには、:wq!と入力し、returnを押します。
  6. 変更を保存せずに終了する場合は、:q!と入力してreturnを押します。
  7. できました。

変更されたchromedriverに移動し、ダブルクリックします。 terminalウィンドウが開きます。出力にkilledが表示されない場合、ドライバーは正常に変更されています。


Perlを使用

以下の行は、cdc_dog_に置き換えます。

Perl -pi -e 's/cdc_/dog_/g' /path/to/chromedriver

置換文字列の文字数が検索文字列と同じであることを確認してください。そうでない場合、chromedriverは失敗します。

Perlの説明

s///gは、文字列を検索し、それを別の文字列でグローバルに置換することを示します(すべての出現を置き換えます)。

例:s/string/replacment/g

そう、

s///は、文字列の検索と置換を示します。

cdc_は検索文字列です。

dog_は置換文字列です。

gは、文字列のすべての出現を置き換えるグローバルキーです。

Perlの置換が機能したかどうかを確認する方法

次の行は、検索文字列cdc_のすべての出現を印刷します。

Perl -ne 'while(/cdc_/g){print "$&\n";}' /path/to/chromedriver

これが何も返さない場合、cdc_は置き換えられています。

逆に、これを使用できます:

Perl -ne 'while(/dog_/g){print "$&\n";}' /path/to/chromedriver

置換文字列dog_chromedriverバイナリにあるかどうかを確認します。そうである場合、置換文字列がコンソールに出力されます。

変更されたchromedriverに移動し、ダブルクリックします。 terminalウィンドウが開きます。出力にkilledが表示されない場合、ドライバーは正常に変更されています。


まとめ

chromedriverバイナリを変更した後、変更されたchromedriverバイナリの名前がchromedriverであり、元のバイナリが元の場所から移動されるか、名前が変更されることを確認します。


この方法での私の経験

ログインしようとしたときにウェブサイトで以前に検出されていましたが、cdc_を同じサイズの文字列に置き換えた後、ログインできました。この方法を使用した後でも、他のさまざまな理由でブロックされる可能性があります。そのため、VPN、別のネットワーク、またはあなたが持っているものを使用して、あなたを検出していたサイトにアクセスする必要があります。

18
colossatr0n

基本的に、Selenium検出の動作方法は、Seleniumで実行するときに表示される事前定義されたjavascript変数をテストすることです。ボット検出スクリプトは通常、任意の変数(ウィンドウオブジェクト上)にWord "Selenium"/"webdriver"を含むものを探し、$cdc_および$wdc_という変数を文書化します。もちろん、これはすべて、どのブラウザーを使用しているかによって異なります。すべての異なるブラウザーは、異なるものを公開します。

私のために、私はクロムを使用したので、私がしなければならなかったすべては、$cdc_がドキュメント変数としてもはや存在しないことを確認することでした。 $cdc_を別の名前で再コンパイルします。)

これは私がchromedriverで変更した関数です:

call_function.js:

function getPageCache(opt_doc) {
  var doc = opt_doc || document;
  //var key = '$cdc_asdjflasutopfhvcZLmcfl_';
  var key = 'randomblabla_';
  if (!(key in doc))
    doc[key] = new Cache();
  return doc[key];
}

(コメントに注意してください、私がしたことはすべて$cdc_randomblabla_に変えました。

ボットネットワークが使用する可能性のある手法のいくつかを示す擬似コードを次に示します。

runBotDetection = function () {
    var documentDetectionKeys = [
        "__webdriver_evaluate",
        "__Selenium_evaluate",
        "__webdriver_script_function",
        "__webdriver_script_func",
        "__webdriver_script_fn",
        "__fxdriver_evaluate",
        "__driver_unwrapped",
        "__webdriver_unwrapped",
        "__driver_evaluate",
        "__Selenium_unwrapped",
        "__fxdriver_unwrapped",
    ];

    var windowDetectionKeys = [
        "_phantom",
        "__nightmare",
        "_Selenium",
        "callPhantom",
        "callSelenium",
        "_Selenium_IDE_Recorder",
    ];

    for (const windowDetectionKey in windowDetectionKeys) {
        const windowDetectionKeyValue = windowDetectionKeys[windowDetectionKey];
        if (window[windowDetectionKeyValue]) {
            return true;
        }
    };
    for (const documentDetectionKey in documentDetectionKeys) {
        const documentDetectionKeyValue = documentDetectionKeys[documentDetectionKey];
        if (window['document'][documentDetectionKeyValue]) {
            return true;
        }
    };

    for (const documentKey in window['document']) {
        if (documentKey.match(/\$[a-z]dc_/) && window['document'][documentKey]['cache_']) {
            return true;
        }
    }

    if (window['external'] && window['external'].toString() && (window['external'].toString()['indexOf']('Sequentum') != -1)) return true;

    if (window['document']['documentElement']['getAttribute']('Selenium')) return true;
    if (window['document']['documentElement']['getAttribute']('webdriver')) return true;
    if (window['document']['documentElement']['getAttribute']('driver')) return true;

    return false;
};

ユーザー@szxによると、16進エディターでchromedriver.exeを開いて、実際にコンパイルを行わずに、手動で置換を実行することもできます。

120

質問と投稿された回答ですでに把握しているように、ここでは "Distil Networks" と呼ばれるアンチWebスクレイピングとBot検出サービスがあります。そして、会社のCEOの インタビュー によると:

新しいボットを作成することはできますが、Seleniumを彼らが使用しているツールとして識別するための方法を考え出したので、そのボットで何回繰り返してもSeleniumをブロックします _。私たちは今、Pythonとさまざまな技術を使ってそれを行っています。ある種類のボットからパターンが発生したことが確認されたら、次にそれらが使用するテクノロジをリバースエンジニアリングし、悪意のあるものとして識別するようにします。

Seleniumをどの程度正確に検出しているのかを理解するには時間と追加の課題がありますが、現時点で確実に言えることは何でしょうか。

  • seleniumで行った行動とは関係ありません。サイトにアクセスするとすぐに検出され禁止されます。アクション間に人為的なランダムな遅延を追加しようとしました、ページがロードされた後に一時停止します - 何も助けになりませんでした
  • それはブラウザの指紋についてでもありません - きれいなプロファイルではなく、シークレットモードで複数のブラウザでそれを試してみました - 何も助けにはなりませんでした
  • インタビューのヒントによれば、これは「リバースエンジニアリング」だったので、これはブラウザで実行されているJSコードによって行われ、Selenium webdriverによって自動化されたブラウザであることが明らかになりました。

明らかに次のように答えとして投稿することにしました。

SeleniumとChromedriverを同時に使用していることをWebサイトで検出できますか?

はい。


また、私が試したことがないのは、古いSeleniumと古いブラウザのバージョンです - 理論的には、Distil Networksのボットディテクタが現在依存しているある時点で、Seleniumに実装または追加されたものがあるかもしれません。それならば、どの時点/バージョンで適切な変更が行われたかを検出し(変更検出器を検出しましょう)、changelogとchangesetsを調べてください。それは彼らがウェブドライバを搭載したブラウザを検出するために何を使っているのか。テストする必要があるのは単なる理論です。

76
alecxe

Wellsfargo.comへの実装例:

try {
 if (window.document.documentElement.getAttribute("webdriver")) return !+[]
} catch (IDLMrxxel) {}
try {
 if ("_Selenium_IDE_Recorder" in window) return !+""
} catch (KknKsUayS) {}
try {
 if ("__webdriver_script_fn" in document) return !+""
19
aianitro

partial interface Navigator { readonly attribute boolean webdriver; };

Navigatorインタフェースのwebdriver IDL属性はwebdriver-activeフラグの値を返さなければなりません。これは最初はfalseです。

このプロパティにより、WebサイトはユーザーエージェントがWebDriverによる制御下にあると判断し、サービス拒否攻撃を軽減するために使用できます。

2017 W3Cエディターズドラフトオブウェブドライバー から直接取得。これは、少なくとも、Seleniumのドライバーの将来の反復が誤用を防ぐために識別可能になることを強く示唆しています。結局のところ、ソースコードなしでは、chromeドライバが正確に検出可能になる原因を正確に知ることは困難です。

9
bryce

Seleniumをchromeという特定のユーザープロファイルで使用してみてください。そうすることで特定のユーザーとしてそれを使用し、必要なものを定義することができます。タグとの違いがわかります。

例えば:

username = os.getenv("USERNAME")
userProfile = "C:\\Users\\" + username + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default"
options = webdriver.ChromeOptions()
options.add_argument("user-data-dir={}".format(userProfile))
# add here any tag you want.
options.add_experimental_option("excludeSwitches", ["ignore-certificate-errors", "safebrowsing-disable-download-protection", "safebrowsing-disable-auto-update", "disable-client-side-phishing-detection"])
chromedriver = "C:\Python27\chromedriver\chromedriver.exe"
os.environ["webdriver.chrome.driver"] = chromedriver
browser = webdriver.Chrome(executable_path=chromedriver, chrome_options=options)

クロムタグリスト ここ

9
Kobi K

難読化されたJavaScriptの結果

私はクロムドライバーのソースコードをチェックしました。それはブラウザにいくつかのJavaScriptファイルを挿入します。
このリンク上のすべてのJavaScriptファイルがWebページに挿入されます。 https://chromium.googlesource.com/chromium/src/+/master/chrome/test/chromedriver/ js/

そこで私はリバースエンジニアリングと 難読化 jsファイルを16進数編集で使いました。これで、Seleniumのアクティビティを明らかにするために、これ以上のJavaScript変数、関数名、および固定文字列が使用されなくなりました。しかし、まだいくつかのサイトとreCaptchaはSeleniumを検出します。
おそらく、彼らはchromedriver jsの実行によって引き起こされた変更をチェックしています:)


編集1:

Chromeの「ナビゲーター」パラメータの変更

私は一時的にchromedriverの使用法を発見する 'navigator'にいくつかのパラメータがあることを発見しました。これらはパラメータです:

  • "navigator.webdriver" 非自動モードでは 'undefined'です。自動モードでは「真」です。
  • "navigator.plugins" ヘッドレスクロムの長さは0です。だから私はプラグインの長さをチェックするプロセスをだますためにいくつかの偽の要素を追加しました。
  • " navigator.languages" はデフォルトのクロム値 '["en-US"、 "en"、 "es"]'に設定されていました。

だから私が必要としていたのは、Webページ上でJavaScriptを実行するためのクロムの拡張機能でした。この記事で提供されている jsコード を使用して拡張機能を作成し、 別の記事 を使用して私のプロジェクトにzip形式の拡張機能を追加しました。 値を正しく変更しました。しかし、まだ何も変わっていません!

私はこれらのような他の変数を見つけませんでした、しかしそれはそれらが存在しないという意味ではありません。それでもreCaptchaはクロームドライバーを検出するので、変更する変数はもっとあるはずです。 次のステップ は、私がしたくない検出器サービスのリバースエンジニアリングであるべきです。

この自動化プロセスにもっと時間をかけたり、他の方法を探したりする価値があるかどうかわかりません。

7
ShayanKM

正しいデータをすべて送信している場合でも(たとえば、Seleniumが拡張機能として表示されない場合は、妥当な解像度/ビット深度などがあります)、訪問者の行動をプロファイルするサービスやツールが多数あります。アクターはユーザーまたは自動化システムです。

たとえば、サイトにアクセスした後すぐにマウスを関連するボタンに直接移動することによって何らかのアクションを実行しようとすると、1秒もかかりませんが、ユーザーが実際に行うことはありません。

また、 https://panopticlick.eff.org/ などのサイトを使用してブラウザのユニーク性を確認することも、デバッグツールとして役立ちます。 Seleniumで実行していることを示す特定のパラメータがあるかどうかを確認するのにも役立ちます。

5
lfaraone

Webアプリケーションのファイアウォールの内側にいるようです。 modsecurityとowaspを見て、それらがどのように機能するのかを確かめてください。実際には、ボット検出回避をどのように行うかということです。それはSelenium Webドライバが目的としているものではありません。それはあなたのWebアプリケーションが他のWebアプリケーションを打たないようにテストするためのものです。それは可能ですが、基本的には、WAFがそのルールセットで探すものを調べ、可能であればSeleniumでそれを避ける必要があります。それでも、どのWAFを使用しているのかわからないため、まだ機能しない可能性があります。あなたは正しい第一歩を踏み出しました、それはユーザエージェントを偽造することです。それでもうまくいかない場合は、WAFが用意されているので、おそらくもっとトリッキーになる必要があります。

編集:他の答えから取られたポイント。まずあなたのユーザーエージェントが実際に正しく設定されていることを確認してください。ローカルWebサーバーにアクセスするか、トラフィックが傍受される可能性があります。

5
Bassel Samman

Webドライバを使用している場合、Firefoxはwindow.navigator.webdriver === trueを設定すると言われています。それは、古い仕様の1つ(例: archive.org )に従っていましたが、 新しいものには見つかりませんでした 付録の非常に曖昧な表現を除いて。

そのためのテストはファイルのSeleniumコードにあります fingerprint_test.js 最後のコメントは "現在はFirefoxでのみ実装されています"と書いていますが、私はいくつかの単純なgrepingでその方向のコードを識別できませんでした現在の(41.0.2)FirefoxリリースツリーにもChromiumツリーにもありません。

2015年1月からのFirefoxドライバ b82512999938でのフィンガープリントに関するより古いコミットへのコメントも見つけました 。そのコードは、昨日javascript/firefox-driver/extension/content/server.jsにダウンロードされたSelenium GITマスターの中にまだ残っています。コメントは、現在のw3c Webドライバーの仕様の中で少し異なる名前の付いた付録にリンクしています。

5
deamentiaemundi

私が見たボット検出は、私が以下の答えで読んだものと比べてより洗練されているか、少なくとも異なるようです。

実験1:

  1. 私はPythonコンソールからSeleniumでブラウザとWebページを開きます。
  2. マウスは、ページが読み込まれるとリンクが表示されることがわかっている特定の場所に既にあります。 マウスを動かさない。
  3. マウスの左ボタンを1回押します(これは、Pythonが実行されているコンソールからブラウザにフォーカスを移すために必要です)。
  4. マウスの左ボタンをもう一度押します(カーソルは特定のリンクの上にあります)。
  5. リンクは正常に開きます。

実験2:

  1. 以前と同様に、PythonコンソールからSeleniumを使用してブラウザとWebページを開きます。

  2. 今回は、マウスでクリックする代わりに、(Pythonコンソールの)Seleniumを使用して、ランダムなオフセットで同じ要素をクリックします。

  3. リンクは開かないが、私はサインアップページに連れて行かれる。

含意:

  • seleniumを介してWebブラウザを開いても、私が人間のように見えるのを妨げることはありません
  • 人間のようにマウスを動かすことは人間として分類される必要はない
  • オフセット付きでSeleniumを介して何かをクリックしてもまだアラームが発生する

不思議に思えるかもしれませんが、アクションがSeleniumから発生したものかどうかを判断できるのではなく、ブラウザ自体がSeleniumを介して開かれたかどうかは関係ありません。それとも、ウィンドウにフォーカスがあるかどうかを判断できますか?誰かが何か洞察を持っているならば、聞くのはおもしろいでしょう。

4
M3RS

いくつかのサイトはこれを検出しています:

function d() {
try {
    if (window.document.$cdc_asdjflasutopfhvcZLmcfl_.cache_)
        return !0
} catch (e) {}

try {
    //if (window.document.documentElement.getAttribute(decodeURIComponent("%77%65%62%64%72%69%76%65%72")))
    if (window.document.documentElement.getAttribute("webdriver"))
        return !0
} catch (e) {}

try {
    //if (decodeURIComponent("%5F%53%65%6C%65%6E%69%75%6D%5F%49%44%45%5F%52%65%63%6F%72%64%65%72") in window)
    if ("_Selenium_IDE_Recorder" in window)
        return !0
} catch (e) {}

try {
    //if (decodeURIComponent("%5F%5F%77%65%62%64%72%69%76%65%72%5F%73%63%72%69%70%74%5F%66%6E") in document)
    if ("__webdriver_script_fn" in document)
        return !0
} catch (e) {}
4
Néstor Lim

次のコードでHTMLページを書きます。 DOMでは、SeleniumがouterHTMLのwebdriver属性を適用していることがわかります。

<html>
<head>
  <script type="text/javascript">
  <!--
    function showWindow(){
      javascript:(alert(document.documentElement.outerHTML));
    }
  //-->
  </script>
</head>
<body>
  <form>
    <input type="button" value="Show outerHTML" onclick="showWindow()">
  </form>
</body>
</html>
2
PC3TJ

私が見つけたもう一つのことは、いくつかのウェブサイトがユーザーエージェントをチェックするプラットフォームを使っているということです。値に "HeadlessChrome"が含まれていると、ヘッドレスモードを使用したときの動作がおかしくなります。

これを回避するには、たとえばJavaでユーザーエージェントの値を上書きします。chromeOptions.addArguments( " - user-agent = Mozilla/5.0(Macintosh; Intel Mac OS X 10_13_6)AppleWebKit/537.36(GeckoのようなKHTML) Chrome/73.0.3683.86 Safari/537.36 ");

1
Adi Ohana

@ Erti-Chris Eelmaaのすばらしい答えに加えて - 迷惑なwindow.navigator.webdriverがあり、それは読み取り専用です。イベントの値をfalseに変更した場合でもイベントにはtrueが含まれます。自動化されたソフトウェアによって駆動されているブラウザがまだ検出される理由はありません。 _ mdn _

変数は、クロムのフラグ--enable-automationによって管理されます。 chromedriverはそのフラグでchromeを起動し、chromeはwindow.navigator.webdrivertrueに設定します。あなたはそれを見つけることができます ここ 。 「除外スイッチ」にフラグを追加する必要があります。例えば(golang):

package main

import (
    "github.com/tebeka/Selenium"
    "github.com/tebeka/Selenium/chrome"
)

func main() {

caps := Selenium.Capabilities{
    "browserName": "chrome",
}

chromeCaps := chrome.Capabilities{
    Path:            "/path/to/chrome-binary",
    ExcludeSwitches: []string{"enable-automation"},
}
caps.AddChrome(chromeCaps)

wd, err := Selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", 4444))
}
1
FDG

私にとってSeleniumでそれをする最も簡単な方法はブラウザのフィンガープリントを送り返すXHRを傍受することです。

しかし、これはSeleniumのみの問題なので、他のものを使用することをお勧めします。 Seleniumは、このようなことをより簡単にするためのものです。

1
pguardiario

私はこのようにjavascriptの "key"変数を変更しています。

//Fools the website into believing a human is navigating it
        ((JavascriptExecutor)driver).executeScript("window.key = \"blahblah\";");

多くのサイトはSeleniumによって廃棄されるのを避けるためにこの変数をチェックするので、Google Chromeと一緒にSelenium Webdriverを使うときいくつかのウェブサイトのために働きます。

0
Juliagu