当社のAIエンジンNeutronが、UCバークレーのCyberGymベンチマークで96.75%のスコアを記録しました。 詳細を見る

セキュリティ

セキュリティ

Android WebViewのaddJavascriptInterfaceのリスク

ケーススタディ:OstorlabのAIペンテストエンジンが、ディープリンク経由で到達可能なAndroid WebViewのJavaScriptブリッジを発見し、それをネイティブUIの操作へと連鎖させます。

はじめに

ハイブリッドモバイルアプリケーションは、WebコンテンツがネイティブのAndroid層と通信できるようにするために、「ブリッジ」に依存することがよくあります。これはネイティブ通知やハードウェアアクセスといった強力な機能を可能にする一方で、大きなアタックサーフェスをもたらします。ネイティブのJavaまたはKotlinのオブジェクトが信頼できないJavaScriptのコンテキストに公開されると、UIの操作、ソーシャルエンジニアリング、あるいはリモートコード実行につながる可能性があります。

WebView.addJavascriptInterface(Object object, String name)メソッドは、与えられたオブジェクトをWebViewのJavaScriptコンテキストに注入し、JavaScriptが@JavascriptInterfaceで明示的に注釈されたネイティブメソッドを呼び出せるようにします。歴史的に見ると、このAPIは4.2より前のAndroidバージョンにおける重大な脆弱性の原因であり、無制限のリフレクションにより、JavaScriptがアプリケーションプロセス内で汎用的なリモートコード実行を達成できました。最近のAndroidバージョンは、明示的な注釈を必須とし、リフレクションによるアクセスを制限することで、この種の問題を緩和しています。しかし、公開されたメソッドが機密性の高い操作を行う場合や、信頼できないJavaScriptがWebView内で実行を許される場合には、このインターフェースは依然として悪用され、信頼境界を越えてネイティブアプリケーションの挙動を操作されるおそれがあります。

JavaScriptブリッジの露出を理解する

この検出結果がなぜ重要なのかを理解するには、組み合わさると強力なエクスプロイトチェーンを生み出す、2つの一般的なAndroidのコンポーネント、すなわちJavaScriptインターフェースとディープリンクのインテント処理を見る必要があります。

1. JavaScriptインターフェース

Androidでは、WebViewコンポーネントによってアプリがWebコンテンツを表示できます。そのWebコンテンツがネイティブのAndroidコードに「話しかけ」られるようにするため、開発者はaddJavascriptInterfaceメソッドを通じて作成される「ブリッジ」を使います。

開発者がwebView.addJavascriptInterface(new MyWebAppInterface(), "Android")を呼び出すと、そのWebView内で実行されるあらゆるJavaScriptが、MyWebAppInterfaceのJavaクラス内のメソッドを、あたかもネイティブのJS関数であるかのように呼び出せます(たとえばwindow.Android.showToast(...))。

リスク:WebViewが(中間者攻撃や悪意のあるリンクを通じて)信頼できないWebサイトを読み込むと、そのWebサイトはネイティブのJavaコードを起動する能力を手にします。

2. ディープリンクの注入

ディープリンクにより、外部のソース(ブラウザーや別のアプリなど)がURIを使ってアプリケーション内の特定の画面を開けます(たとえばmyapp://profile)。

アプリケーションの「ゲート」の守りが甘いと、javascript: URIをディープリンクとして受け入れてしまうことがあります。たとえば、次のようなものです。 intent://target_activity?url=javascript:alert(window.Android.showToast('Hacked'))

アプリがこのURLをWebViewに無造作に読み込むと、それは単にWebページを読み込んでいるのではなく、アプリケーションの安全なコンテキストの内部で任意のコードを直接実行していることになります。

この2つの要素が衝突すると、攻撃者はリモートからアプリに「手を伸ばす」ことができます。作成したリンクをユーザーに送ることで、攻撃者はアプリを強制的に開かせ、内部のWebViewに悪意のあるJavaScriptを注入し、そのうえでブリッジを使ってネイティブ機能を操作します。

Ostorlab Pentest Engineの概要

Ostorlab Pentest Engineは、人工知能を活用し、熟練した人間のペンテスターの推論と手法を模倣するよう設計された、自律型の攻撃的セキュリティエージェントです。静的でルールベースのチェックに依存する従来のスキャナーとは異なり、このエンジンは動的な「推論と行動(Reason and Act)」のフレームワークを使ってアプリケーションのアタックサーフェスを探索します。

仕組み:自律的なループ

このエンジンは、継続的で反復的なサイクルを通じて動作し、本ケーススタディで取り上げるJavaScriptブリッジの露出のような複雑な脆弱性に対応できます。

  • リスクモデリングと仮説の生成:P.A.S.T.A.のような手法を用いて、エンジンはまず対象の脅威モデルを構築します。単にペイロードを大量に送るのではなく、具体的な仮説(たとえば「このディープリンクはJavaScriptを実行してネイティブのブリッジに到達できるか」)を生成します。
  • 専門化されたサブエージェント(実行役):エンジンは、Ostorlab OXOプラットフォームを通じて、専門化されたサブエージェント群を統制します。これらの実行役は、monkeyテスター、クローラー、ファザー、テイントエンジンなどのツールを使用します。
  • 実行時の計装と動的な対話:エンジンは、ライブで管理された実行環境の中で動作し、技術スタック(Java、Swift、C/C++、Flutter)をまたいで計装を重ねます。これにより、ネイティブの挙動に「フック」し、2FA/OTPに対応した認証後の領域を含む複雑なUIのフローをたどり、Webとネイティブ層の間を流れるデータをリアルタイムで検査できます。
  • 敵対的検証:精度を高め、誤検知を減らすため、エンジンには専用の敵対的検証パスが含まれています。検出結果を独立して再検証し、脆弱性が再現可能であり、真のリスクをもたらすことを確認します。

アーティファクトと観察結果を精選したメモリとして保持することで、ペンテストエンジンは検出結果を「連鎖」させられます。今回のケースでは、エンジンは単にディープリンクを見つけただけでなく、そのディープリンクがJavaScriptペイロードの配送手段として使え、それが列挙済みのネイティブインターフェースと対話できると推論しました。

攻撃の物語:JavaScriptブリッジの露出を発見する

最近のベンチマークテストの際、OstorlabのPentest Engineは、あるハイブリッドアプリケーションのWebView実装にギャップを特定しました。アプリケーションのディープリンクハンドラーを体系的に調べることで、WebView内で実行されるJavaScriptが、明示的なユーザーの同意なしにネイティブのUI要素を起動できる、公開されたJavaScriptインターフェースを発見しました。

ステップ1:ブリッジの発見と列挙

エンジンの最初の目的は、WebViewのJavaScriptコンテキストに注入されたネイティブオブジェクトを特定することで、利用可能なアタックサーフェスをマッピングすることでした。

ブリッジの発見:JavaScriptコンテキストから、公開されているブリッジのオブジェクトとメソッドを特定する。目的:アクセス可能なメソッドを列挙し、ネイティブのアタックサーフェスを把握する。

実行サマリー: エンジンはObject.getOwnPropertyNames()を使ってグローバルなwindowオブジェクトのプロパティを一覧化し、カスタムのインターフェースを特定しました。

結果: Androidという名前のブリッジオブジェクトが発見されました。さらに列挙すると、アクセス可能なメソッドが1つ特定されました。showToast(String message)です。

結論: アプリケーションはネイティブのブリッジを公開しています。メソッドの一覧は最小限ですが、オリジンの制限がないということは、WebView内に読み込まれるあらゆるページ(ディープリンク経由で注入されたものを含む)が、ネイティブのUIロジックを呼び出せることを意味します。

ステップ2:注入ベクトルの検証

ブリッジが存在することがわかったエンジンは、外部の信頼できないソースからそれと対話する手段を特定する作業に移りました。その結果、アプリケーションのディープリンクハンドラーが、URIスキームをサニタイズせずに受信インテントを処理するよう構成されていることを発見しました。

javascript: URIを使ったディープリンクの注入を通じて、Androidブリッジにアクセスできるかを検証する。目的:WebViewが外部のインテントから任意のコードを実行するかを確認する。

実行サマリー: エンジンは、発見したブリッジを呼び出すよう設計したjavascript:ペイロードを使って、脆弱なアクティビティ(Activity2)に悪意のあるインテントを送信しました。 adb shell am start -W -a android.intent.action.VIEW -n com.target.app/.Activity2 -d "javascript:Android.showToast('BRIDGE_ACCESS_TEST')"。

結果: このコマンドはアプリケーションによって正常に処理されました。端末の画面に「BRIDGE_ACCESS_TEST」というテキストのネイティブのトーストメッセージが表示され、Logcatのエントリがcom.target.appパッケージからのメソッド呼び出しを裏付けました。

結論: 注入ベクトルは完全に検証されました。アプリケーションはインテントを通じて渡されるjavascript:やdata: URIを拒否しないため、あらゆる外部アプリケーションが、WebViewに対して、ネイティブのJavaインターフェースと直接対話するコードを強制的に実行させることができます。

ステップ3:権限昇格の調査(リフレクションと注入)

ブリッジがアクセス可能であることが確認されたエンジンは、UIの操作を超えて、ネイティブコードの実行やコマンドインジェクションといったより深刻な影響を特定しようと試みました。目的は、showToastメソッドやブリッジ自体を、Androidのサンドボックスをバイパスするためのプリミティブとして利用できるかどうかを見極めることでした。

showToastメソッドを通じたリフレクションまたはコマンドインジェクションを使ってサンドボックスをバイパスし、ネイティブコードの実行を達成することを試みる。

実行サマリー: エンジンは、いくつかの高度な悪用パターンを体系的にテストしました。

  1. リフレクションのテスト:getClass()メソッドにアクセスし、forName('java.lang.Runtime')を使ってシステムコマンドを実行しようと試みました。
  2. コマンドインジェクション:showToastのパラメーターにシェルのメタ文字やコマンドの区切り文字(たとえば;、&&、`)を注入しようと試みました。
  3. プロトタイプ汚染:ブリッジオブジェクトのプロトタイプに悪意のあるメソッドを注入しようと試みました。

結果: すべての権限昇格の試みはブロックされました。

  • リフレクション:getClass()へのアクセスは制限されており、Runtime.exec()に到達するためにメソッドを連鎖させる試みは失敗しました。
  • コマンドインジェクション:ネイティブのshowToastの実装はすべての入力をそのままのCharSequenceとして扱い、悪意のある文字列を実行するのではなく、画面上にプレーンテキストとして表示しました。
  • 不変性:ブリッジオブジェクトは不変であることがわかり、プロトタイプ汚染やメソッドのオーバーライドが防がれていました。

結論: メソッドレベルでのセキュリティ制御は効果的です。ブリッジは公開されているものの、「安全に実装」されており、影響は一時的なUIの効果に限られ、ネイティブコードの実行やデータの持ち出しへの昇格が防がれています。

ステップ4:実際の影響の確認(ソーシャルエンジニアリングのチェーン)

直接的なネイティブへの昇格はブロックされていることをエンジンは確認しましたが、方向を転換し、実際のビジネス上のリスク、すなわちソーシャルエンジニアリングを検証しました。ネイティブのUI要素を表示するというブリッジの能力を利用して、エンジンは、攻撃者がユーザーの信頼を操作して認証情報の窃取やマルウェアの配布を促し得る様子を実証しました。

認証不要のフィッシングコンテンツと、ブリッジ経由で起動される「公式」のネイティブ通知を組み合わせた多段階の攻撃チェーンを実行し、ソーシャルエンジニアリングの影響を評価する。

実行サマリー: エンジンは、現実のフィッシングシナリオを模倣するため、2段階の「連鎖攻撃」を統制しました。

  1. フィッシングへのリダイレクト:ディープリンクを使って、WebViewに外部の悪意のあるURLを強制的に読み込ませました。 adb shell am start -n com.target.app/.Activity2 -d "https://attacker.com/phishing.html"

  2. 偽の通知の注入:リダイレクトの直後に、ブリッジ経由で緊急を装ったネイティブのトーストメッセージを起動しました。 adb shell am start -n com.target.app/.Activity2 -d "javascript:Android.showToast('🔒 New message: Account verification required')"

結果: ユーザー体験は乗っ取りに成功しました。アプリケーションはフィッシングページを起動すると同時に、公式を装ったネイティブ通知を表示しました。これにより、「アカウントの確認」の要求が、悪意のあるWebサイトではなく、信頼されたローカルのアプリケーションから来ているという強力な錯覚が生まれます。

結論: これは、ビジネスおよびユーザーのプライバシーへの影響の高い可能性を裏付けています。データの持ち出しやコード実行がなくても、ブリッジは、アプリケーションの本当の状態についてユーザーを欺くことで、「スケアウェア」の配布や認証情報の収集に利用され得ます。

最終レポート

1. エグゼクティブサマリー

Ostorlab Pentest Engineは、対象アプリケーションのBankWebViewKtコンポーネントにJavaScriptブリッジの露出を発見しました。Androidブリッジオブジェクトは、オリジンの検証やソースの確認を一切行わずにWebViewに注入されています。この脆弱性により、あらゆるJavaScriptのコンテキスト(認証不要のディープリンクを通じて注入されたものを含む)が、ネイティブのshowToastメソッドを呼び出せます。メソッドレベルでの効果的なサンドボックス化によってネイティブコードの実行とコマンドインジェクションがブロックされていることをエンジンは確認しましたが、この脆弱性は、精度の高いソーシャルエンジニアリングやユーザーを欺く行為の可能性があるため、依然として影響度の高いものです。

2. 手法

ペンテストエンジンは、ネイティブのブリッジのセキュリティをテストするために、方法論的で多段階のプロセスに従いました。

  • ブリッジの発見:WebView内のwindowオブジェクトのプロパティを列挙することで、カスタムのネイティブインターフェースを特定しました。
  • ベクトルの分析:Activity2がjavascript: URIを含むディープリンクをサニタイズせずに処理し、外部コードの侵入口を提供していることを発見しました。
  • 静的解析:com.target.app/BankWebViewKt.java内の脆弱なブリッジの注入箇所を正確に突き止めました。
  • 昇格の調査:最大の悪用可能性を見極めるため、Javaのリフレクション、コマンドインジェクション、プロトタイプ汚染を体系的にテストしました。
  • 影響シナリオのテスト:フィッシングのリダイレクトと偽のネイティブ通知を連鎖させることで、ソーシャルエンジニアリングのリスクを検証しました。

3. 検出結果

  • 無制限のJavaScriptインターフェースの露出:Androidブリッジはオリジンの検証なしにWebViewに注入されており、ディープリンク経由で注入されたものを含む、読み込まれたあらゆるページからアクセス可能になっています。これは、Webコンテンツとネイティブ層の間に適切な信頼境界を課せていないことを表しています。
  • 保護されていないディープリンク:アプリケーションは、javascript:やdata: URIがサニタイズされないままインテントを通じて処理されることを許しています。これにより、外部アプリがブリッジのメソッドを直接呼び出せるようになり、ネイティブのUIを操作する手軽な手段が提供されています。
  • 効果的なブリッジレベルのサンドボックス化:ブリッジの露出をシステムレベルのコード実行へと昇格させる試みは失敗しました。showToastメソッドはすべての入力をそのままの文字列として扱い、JavaScriptインターフェースのオブジェクトは不変であるため、リフレクション、プロトタイプ汚染、コマンドインジェクションが防がれています。
  • レート制限の欠如:ブリッジは、ディープリンク経由の繰り返しの呼び出しを制限なく許します。これはコード実行にはつながりませんが、素早いUIの操作や通知の「スパム」を可能にし、ソーシャルエンジニアリングのシナリオで利用され得ます。

4. 修復

これらの検出結果に対処するため、次の対応が推奨されました。

  • アクセスの削除または制限:ブリッジが不要であれば、addJavascriptInterfaceのブロックを完全に削除する。
  • オリジンの検証:ブリッジが必要な場合は、信頼できるドメインの厳格な許可リストを実装し(たとえばSecureWebViewClientを使用)、メソッドの実行を許可する前に現在のオリジンを検証する。
  • ディープリンクのサニタイズ:Activity2のディープリンクハンドラーを更新し、javascript:またはdata:スキームで始まるインテントデータを拒否する。
  • セキュリティの堅牢化の適用:本番ビルドでのファイルアクセスやデバッグなど、不要なWebViewの機能を無効化し、全体的なアタックサーフェスを減らす。

5. 結論

本ケーススタディは、「安全に実装」されたブリッジであっても、外部からの入力にさらされたままにすると、重大なセキュリティリスクをもたらし得ることを示しています。インターフェースの発見から機能するソーシャルエンジニアリングのチェーンの作成に至るまで、攻撃者の論理的な進行を模倣することで、OstorlabのPentest Engineは、ハイブリッドインターフェースを安全にするために必要な決定的なエビデンスを提供しました。