web-dev-qa-db-ja.com

検出Chrome JavaScriptからヘッドレスモードで実行

Chrome 59のリリースで、「ヘッドレス」モードは 現在利用可能 LinuxおよびmacOSの安定ビルドで(そしてすぐにWindowsもChrome 60)。これにより、ChromeのUIは表示されず、自動テストのための優れた機能を備えたフル機能バージョンを実行できます。 例を示します。

chrome --headless --disable-gpu --dump-dom https://stackoverflow.com/

JavaScriptテストランナーでは、使用されているブラウザーについて可能な限り多くの情報を記録して、問題を切り分けます。たとえば、現在のブラウザプラグインを含む、navigatorの多くのプロパティを記録します。

JSON.stringify(Array.from(navigator.plugins).map(p => p.name))
["Chrome PDF Viewer","Widevine Content Decryption Module","Shockwave Flash","Native Client","Chrome PDF Viewer"]

私の理解では、Chromeshouldはヘッドレスモードでも同じように動作しますが、新しいものには懐疑的である十分な経験がありますレンダリングパイプラインを大幅に変更する可能性のある機能。

ここでは、両方のモードでテストを実行します。テストランナーに、ヘッドレスモードが使用されているかどうかを記録したいと思います。この情報をテスト構成で渡すこともできますが、テストランナー自体に組み込むことができる純粋なJavaScriptソリューションが必要です。ただし、ヘッドレスモードがアクティブかどうかを示すブラウザーインターフェイスを見つけることができませんでした。

ChromeがJavaScriptからヘッドレスモードで実行されているかどうかを検出する方法はありますか?

51
Jeremy Banks

確認してもいい - navigator.webdriver プロパティ:

webdriverインターフェイスのnavigator読み取り専用プロパティは、ユーザーエージェントが自動化によって制御されているかどうかを示します。

...

navigator.webdriverプロパティは次の場合にtrueです。

Chrome--enable-automation または --headlessフラグが使用されます。
Firefoxmarionette.enabled設定または--marionetteフラグが渡されます。

W3C WebDriverの推奨事項 説明 次のとおり:

navigator.webdriver連携するユーザーエージェントがWebDriverによって制御されていることをドキュメントに通知する標準的な方法を定義します。たとえば、自動化中に代替コードパスをトリガーできます。

16
Justas

user agent文字列 HeadlessChromeの代わりにChromeを含む 。これはおそらくあなたが探すことを意図している信号なので、次のように使用できます:

/\bHeadlessChrome\//.test(navigator.userAgent)

その他の興味深い信号には次のものがあります。

  • ヘッドレスの場合、window.chromeは未定義のようです。
  • [innerWidth, innerHeight][800, 600]headless_browser.ccにハードコードされています)、[outerWidth, outerHeight][0, 0](通常は発生しません)です。
29
Josh Lee

Antoine Vastelによるこの記事 を読むだけで、いくつかの方法が提供されます。

  • /HeadlessChrome/.test(window.navigator.userAgent)を使用してユーザーエージェントをテストしますが、これは簡単になりすます
  • navigator.plugins.length == 0を使用したプラグインのテスト
  • navigator.languages == ""を使用した言語のテスト
  • webGLベンダーおよびレンダラー情報のテスト(興味深い詳細については記事を参照)
  • modernizrが検出したサポート機能のテスト:「ヘアライン」はサポートされていないようです(hidpi/retinaヘアラインは、hidpi画面で物理的に1pxであるため、幅が1px未満のCSS境界線です)。テストは!Modernizr["hairline"]です。
  • 欠落している画像のプレースホルダーのサイズをテストします。無効なURLの画像を挿入し、image.width == 0 && image.height == 0image.onerrorをテストします(これが最も堅牢であることがわかりました)。

Googleの動機について話すことができません(Headless ChromeはWebアプリケーションのテストを容易にすることだけですか?うーん... )、しかし、これはいつか修正されるかもしれないバグのリストとして見ることができたので、それらのテストがどれくらい長く機能するか疑問に思う必要があります:)

8
Hugues M.

私がこれまでに持っている最良の解決策は、このハックです。 prodコードでは使用しませんが、テストでは使用します。

Chromeのポップアップブロッカーは通常、すべてのWebサイトで有効になっていますが、ヘッドレスモードでは無効になっています。ヘッドレスモードになるためのかなり正確なプロキシとして、ポップアップを開く機能を使用できます。実装は簡単です。ウィンドウをopen(...)して、nullオブジェクトの代わりにWindow(ブロックされたことを示す)を取得するかどうかを確認してください。開いた場合は、できるだけ早く閉じます。

_function canPopUp() {
  var w = open("");
  if (w !== null) {
    w.close();
    return true;
  } else {
    return false;
  }
}

var isHeadless = canPopUp;
_

簡単な例として、_--headless_フラグを使用して、または使用せずに次を試すことができます。

chrome --headless --disable-gpu --dump-dom 'data:text/html,<!doctype html><body><script>document.body.innerHTML = `headless: ${open("") !== null}`;</script>'

5
Jeremy Banks

navigator.pluginsには、ブラウザ内に存在するプラグインの配列を含める必要があります(Flash、ActiveX、またはJavaアプレット)など。headlessブラウザの場合、null可能です。

セキュリティチェックの一環として、alertを使用できます。ヘッドレスの場合は無視されます。

var start = Date.now();
alert('Press OK');
var elapse = Date.now() - start;
if (elapse < 15) {
    console.log("headless environment detected");
}

ヘッドレスブラウザーを検出するためのいくつかの手法については、OWASP AppSecUSA 2014トークHeadless Browser Hide&Seekvideoslides )by Sergey Shekyan and Bei Zhang。

4
FieryCat