DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

F5エコシステム | 2018年9月17日


Shapeでは、数多くの不審なJavaScriptに遭遇します。ページに悪意を持って挿入されたスクリプトを発見することもあれば、助言を求めるお客さまからスクリプトが送られてくることや、F5のサービスの一部に明確に言及していると思われるWeb上のリソースをセキュリティチームが見つけることもあります。日常業務の一環として、スクリプトの動作や仕組みを理解するため、すぐに詳しく調査します。通常、スクリプトはミニファイされ、多くの場合は難読化されているため、本格的な詳細分析に取りかかれる状態にするには、必ず複数段階の修正が必要です。

最近まで、この分析を行う最も簡単な方法は、手動で編集できるローカルキャッシュ環境を使用するか、プロキシを使ってコンテンツをリアルタイムに書き換えることでした。ローカル環境は最も便利ですが、Webサイトを別の環境で必ずしも完全に再現できるとは限らず、作業を始めるだけでもトラブルシューティングに延々と時間を費やすことがよくあります。プロキシは非常に柔軟ですが、通常は扱いが煩雑で、移植性もあまり高くありません。各自が自分の環境に合わせた独自の設定を使用しており、使い慣れたプロキシも人によって異なります。そこで、ChromeとそのDevToolsプロトコルを使用し、リクエストとレスポンスの発生時に介入してリアルタイムに変更するようになりました。この方法はChromeが動作するあらゆるプラットフォームで利用でき、さまざまな問題を回避できるうえ、一般的なJavaScriptツールともスムーズに連携します。この記事では、 ChromeのDevToolsプロトコルを使用してJavaScriptをリアルタイムにインターセプトし、変更する方法を説明します。

ここではnodeを使用しますが、devtoolsのフックに簡単にアクセスできるのであれば、内容の多くは任意の言語に応用できます。

まず、Chromeのスクリプト操作を試したことがない方には、Eric Bidelman氏による優れた Headless Chromeスタートガイドがおすすめです。そこに記載されているヒントは、Headless ChromeとGUI版Chromeの両方に適用できます(ただし、1つだけ注意点があり、次のセクションで説明します)。

Chromeの起動

簡単に実行できるよう、npmのchrome-launcherライブラリを使用します。

DevToolsプロトコルを介したChromeでのレスポンスのインターセプトと変更

chrome-launcherは、その名のとおりの動作をし、ターミナルで使い慣れたコマンドラインスイッチをそのまま渡すことができます(詳細な一覧はこちらで管理されています)。ここでは、次のオプションを渡します。

–window-size=1200,800

  • ウィンドウサイズを適切な値に自動設定します。

–auto-open-devtools-for-tabs

  • 頻繁に使用するため、開発者ツールを自動的に開きます。

–user-data-dir=/tmp/chrome-testing

  • 固定のユーザーデータディレクトリを設定します。(本来は不要であることが理想ですが、Mac OSXの非ヘッドレスモードでは、このフラグがないとリクエストをインターセプトできないようです。より良い方法をご存じでしたら、Twitterでお知らせください!)
DevTools Protocolを介したChromeレスポンスのインターセプトと変更

スクリプトを実行して、Chromeを開けることを確認してください。次のような画面が表示されます。

DevToolsプロトコルを介したChromeレスポンスのインターセプトと変更

Chrome Devtools Protocolの使用

これは「Chrome debugger protocol」とも呼ばれ、Googleのドキュメントでは両方の用語が同じ意味で使われているようです。まず、npmを使用してパッケージchrome-remote-interfaceをインストールします。これにより、DevTools Protocolを操作するための便利なメソッドを利用できます。さらに詳しく調べる場合は、プロトコルのドキュメントをすぐ参照できるようにしておいてください。

DevTools Protocolを介してChromeでレスポンスをインターセプトおよび変更

CDPを使用するにはデバッガーポートに接続する必要があります。ここでは chrome-launcher ライブラリを使用しているため、 chrome.port から簡単にアクセスできます。

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

プロトコル内の多くのドメインは、最初に有効にする必要があります。まずはRuntimeドメインを有効にしてconsole APIに接続し、ブラウザ内のconsole呼び出しをコマンドラインに出力できるようにします。

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

これでスクリプトを実行すると、すべてのコンソールメッセージをターミナルにも出力する、完全に機能するChromeウィンドウが表示されます。これだけでも、特にテストには非常に便利です!

リクエストのインターセプト

まず、インターセプトする対象を登録するため、RequestPatternsのリストをsetRequestInterceptionに送信する必要があります。「Request」ステージまたは「HeadersReceived」ステージでインターセプトできますが、実際にレスポンスを変更するには「HeadersReceived」まで待つ必要があります。リソースタイプは、開発者ツールのネットワークパネルで一般的に表示されるタイプに対応しています。

上記のNetworkドメインも、Runtimeと同様に、同じ配列にNetwork.enable()を追加して有効にしてください。

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

イベントハンドラーの登録は比較的簡単です。インターセプトされた各リクエストには、そのリクエストに関する情報の照会や、最終的な処理続行の指示に使用できる ​interceptionId が付与されます。ここでは、インターセプトしたすべてのリクエストに介入し、ターミナルに記録するだけです。

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

リクエストの変更

リクエストを変更するには、base64文字列をエンコードおよびデコードするためのヘルパーライブラリをインストールする必要があります。利用できるライブラリは多数あるため、任意のものを選択できます。ここではatobとbtoaを使用します。

DevTools Protocolを介してChromeでレスポンスをインターセプトおよび変更

レスポンスを処理するAPIは、やや扱いにくい仕様です。レスポンスを処理するには、単にレスポンスをインターセプトするのではなく、リクエストのインターセプト時にレスポンス処理のロジックをすべて組み込み、その後、インターセプトIDを使用してボディを照会する必要があります。これは、ハンドラーが呼び出された時点ではボディを取得できない可能性があるためです。この方法により、必要なボディが取得可能になるまで明示的に待機できます。また、ボディがbase64でエンコードされている場合もあるため、そのまま渡さず、事前に確認してデコードしてください。

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

ここからは、JavaScriptを自由に変更できます。コードはレスポンスの処理途中に介在するため、リクエストされたJavaScript全体にアクセスし、変更後のレスポンスを返すことができます。便利ですね。変更したコードがブラウザーで実行されたときにターミナルへメッセージが表示されるよう、JSの末尾にconsole.logを追加して少し調整します。

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

変更した本文だけをそのまま渡すことはできません。内容が、元のリソースとともに送信されたヘッダーと競合する可能性があるためです。テストと調整を進めている段階では、伝達が必要なその他のヘッダー情報を詳しく検討する前に、まず基本的な部分から始めるとよいでしょう。必要に応じて、イベントハンドラーに渡される ​responseHeaders を介してレスポンスヘッダーにアクセスできますが、ここでは後で簡単に操作や編集ができるよう、必要最小限のヘッダーセットを配列として作成します。

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

新しいレスポンスを送信するには、HTTPステータス行を含む完全なHTTPレスポンスを作成してbase64でエンコードし、rawResponseプロパティを介してcontinueInterceptedRequestに渡すオブジェクトに含める必要があります。

DevToolsプロトコルを介したChromeでのレスポンスのインターセプトと変更

ここでスクリプトを実行してインターネット上を移動すると、スクリプトがJavaScriptをインターセプトしたときや、変更したJavaScriptがブラウザで実行され、​console.log()の出力がチュートリアルの冒頭で作成したフックを通じて送られてきたときに、ターミナルには次のような内容が表示されます。

DevTools Protocolを介してChromeでレスポンスをインターセプトおよび変更

基本的な例の完全な動作コードはこちらです:

DevTools Protocolを介したChromeでのレスポンスのインターセプトと変更

次のステップ

まず、ソースコードを整形して表示することから始められます。これは、リバースエンジニアリングに着手する際に常に役立つ方法です。もちろん、最近のほとんどのブラウザでも整形できますが、ブラウザやそのバージョンが異なっても一貫性を保ち、ソースを分析しながら情報を関連付けられるようにするには、変更の各手順を自分で管理することをお勧めします。見慣れない難読化されたコードを調べる際は、変数や関数の目的が分かり始めた段階で、それらの名前を変更するとよいでしょう。JavaScriptを安全に変更するのは決して簡単ではなく、それだけで1本のブログ記事になるテーマですが、ひとまず一般的な圧縮や難読化の手法を元に戻すには、​unminifyのようなツールを使用できます。

npmを使用してunminifyをインストールし、新しいJavaScriptの本体を​unminifyの呼び出しでラップすると、実際の動作を確認できます。

DevToolsプロトコルを介してChromeでレスポンスをインターセプトして変更

変換については、次回の記事でさらに詳しくご紹介します。ご質問やコメント、便利なテクニックなどがありましたら、ぜひTwitterからご連絡ください。


共有

関連するブログ記事

F5 Application Study Tool:OpenTelemetryによるF5 BIG-IP環境の監視
F5エコシステム | 2025/04/15

F5 Application Study Tool:OpenTelemetryによるF5 BIG-IP環境の監視

F5の新しいオープンソースツールは、BIG-IP環境を詳細に可視化し、データを追跡するとともに、強力でカスタマイズ可能なインサイトを得るための基盤を提供します。

F5 BIG-IPでAI防御を実現
F5エコシステム | 2024/11/13

F5 BIG-IPでAI防御を実現

F5 BIG-IP Advanced WAF、BIG-IP APM、BIG-IP SSL Orchestratorが、生成AIアプリ向けに包括的なセキュリティソリューションを提供する仕組みをご覧ください。

F5 Advanced WAFによるGraphQL APIの保護
F5エコシステム | 2021/08/31

F5 Advanced WAFによるGraphQL APIの保護

ここ数年、多くの組織がデジタルトランスフォーメーションを進めており、COVID-19のパンデミックによってその動きは加速しています。

アプリケーションサービスの現状 通信業界版:リーダーとしての台頭
F5エコシステム | 2019/02/19

アプリケーションサービスの現状 通信業界版:リーダーとしての台頭

通信ネットワークが進化し、さまざまな業界の幅広いユースケースに対応するなか、通信業界の回答者がテクノロジーリーダーとしての存在感を高めていることがわかります。

デジタルトランスフォーメーションは、単なるペーパーレス化ではない
F5エコシステム | 2017/07/10

デジタルトランスフォーメーションは、単なるペーパーレス化ではない

デジタルトランスフォーメーションは、単なるペーパーレス化ではありません。真のモダナイゼーションにアプリケーションアーキテクチャとセキュリティの再構築が必要な理由を、F5ブログでご覧ください。

やめましょう。もう本当にやめましょう。HTTPSはHTTPより高速ではありません。
F5エコシステム | 2016/09/19

やめましょう。もう本当にやめましょう。HTTPSはHTTPより高速ではありません。

もうやめましょう。HTTPSはHTTPより高速ではありません。プロトコルのパフォーマンスに関する微妙な違いと、暗号化トラフィックを適切に最適化する方法については、F5ブログをご覧ください。