こんにちは、SSTでWeb脆弱性診断用のツール(スキャンツール)開発をしている坂本(Twitter, GitHub)です。
本記事では Android で burp などMITM型*1 のProxyを設定する方法と、Android版 Chrome 99 以上で発生する NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
の回避方法を紹介します。
弊社では診断対象となるWebアプリのHTTP(S)通信を MITM型Proxy で取得し、検査用に編集してサーバに送っています。 「Proxyを挟めること」が診断を進める上での必須要件であり、Proxyを挟めないと診断はもとより、アプリの挙動の調査すらできません。 この「Proxyを挟む」のが難しくなっていると実感するのが、Android のProxy設定になります。
そこで本記事では、2022年時点のスナップショットとして Android におけるMITM型 Proxy 設定のポイントを簡単に紹介したいと思います。
またMITM型ProxyのCA証明書に関連し、Android版 Chrome 99 以上で発生するようになった NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
の回避方法も紹介します。
検証環境:
- Google Pixel 6a (Android 13, ビルド TP1A.220905.004.A2)
- Android Chrome 108.0.5359.128
- Burp Suite Community Edition (2022年のどこかのバージョン)
- Magisk v25.2
- Magisk Trust User Certs v0.4.1
- MagiskBypassCertificateTransparencyError v0.0.1
- 0. 概要
- 1. 端末のroot化とMagisk導入
- 2. Proxy 設定
- 3. "Magisk Trust User Certs" モジュールによるCA証明書のインストール
- 4. "MagiskBypassCertificateTransparencyError" モジュールの導入
- まとめと感想
0. 概要
Androidでも利用できるHTTP(S) Proxy ツールとしては、筆者が知っているものだけでも以下があります。
これらは暗号化されたHTTPS通信についても復号して平文を確認できる "MITM"(man-in-the-middle)型Proxyでもあります。 暗号化されたHTTPS通信をどうやって復号しているのか?については Burp の TLS Pass Through 設定の使い所と仕組み で解説していますのでそちらを参照してください。 重要なのは、MITM型Proxyが内蔵しているCA(Certificate Authority)証明書をブラウザに信頼してもらわないとHTTPS通信が復号もできず、そもそも通信すらできない点です。
- PC用ブラウザ(Chrome/Firefox/Edge/Safariなど) の場合
- OS設定やブラウザ自身のメニューから簡単にCA証明書をインストールできます。
- ブラウザ側も、ユーザ自身がインストールしたCA証明書については特に問題なく信頼してくれます。(2022年末時点)
- 参考: burpのPC用ブラウザ向けCA証明書インストール手順
- iPhone/iOS端末の場合
- MITM型ProxyのCA証明書をメール添付ファイルなどで送れば、「プロファイル」として簡単にインストールできます。
- 「設定」→「情報」→「証明書信頼設定」→「ルート証明書を全面的に信頼する」で証明書毎に個別にON/OFFするのを忘れずに。(この設定を忘れがちで、「あれ?プロファイルインストールしたけどHTTPSでエラーになるぞ?」とよくトラブルになります)
- SSTエンジニアブログでも日本語解説として詳しく紹介しております。
- 参考: burpのiPhone/iOS向けCA証明書インストールとProxy設定手順
- Androidの場合
- Android 7 (Nougat) 以降、CA証明書はOS管理のディレクトリにインストールする必要があります。
- このため Android端末のroot化が必須 となります。
- またインストール方法も面倒で、CA証明書のファイル名など独特のルールがあります。
- これらの手間を緩和するには、root化用ツールセットである Magisk とそのモジュールである "Magisk Trust User Certs" モジュールを使うと便利です。
- さらに Android Chrome 99 以降では、それだけでは
NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
エラーが出るようになってしまっため、回避するための設定も必要です。 - 参考: burpのAndroid向け CA証明書インストールとProxy設定手順
このように MITM型Proxy のCA証明書では、Androidにおけるややこしさが際立っています。
Proxy 設定についても、AndroidアプリではOS側の(= WiFi の) Proxy設定に従わないアプリがあったりします。 こうしたアプリの通信についても Proxy を通せるような Android アプリがあるのですが、これも一部でroot化必須だったりします。
まとめると、Android においてMITM型Proxyを安定して使うためには、以下のポイントをおさえる必要があります。
- 端末のroot化とMagisk導入
- root化しないと、MITM型ProxyのCA証明書をインストールして信頼させることができません。
- Proxy設定用アプリでroot化必須のものがあります。
- Proxy 設定
- OS側のWiFi Proxy 設定を無視するアプリがあるため、別途Proxy設定用アプリが必要です。
- "Magisk Trust User Certs" モジュールによるCA証明書のインストール
- Android 7 (Nougat) 以降のCA証明書インストールが簡単にできるようになります。
- "MagiskBypassCertificateTransparencyError" モジュールの導入
- Android Chrome 99 以降の
NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
エラーの回避で必要です。
- Android Chrome 99 以降の
それでは順番に紹介していきます。
1. 端末のroot化とMagisk導入
Android端末のroot化手順については機種ごとに差異が大きいため、以下に Pixel6a で筆者が作業したときの大まかな流れだけ紹介しておきます。
- Android Studio などでADBコマンドをインストール
- Android端末側でADBデバッグを有効化
- Google USB Driver をインストールしてADBデバッグ接続確認
- 「OEMロック解除」オプションを有効化
- bootloaderアンロック
- ファクトリ/OTAイメージの boot.img ダウンロード
- Magiskをインストールして boot.img にパッチ適用
- 端末を fastboot モードで起動してWindowsホストとUSB接続し
fastboot flash boot <パッチを適用したboot.img>
実行
実際の手順などは以下の資料を参考にしました。 Androidのバージョンによって、さらに同じバージョンでもビルド番号やビルド時期によって資料にあるとおりに動かなかったりしますので、臨機応変な対応が必要となります。
Android実機端末へのADB接続関連:
ハードウェア デバイス上でのアプリの実行 | Android デベロッパー | Android Developers
Android Debug Bridge(adb) | Android デベロッパー | Android Developers
Google USB ドライバを入手する | Android デベロッパー | Android Developers
OEM USB ドライバのインストール | Android デベロッパー | Android Developers
Pixel6a のファクトリ/OTAイメージ:
Factory Images for Nexus and Pixel Devices | Google Play services | Google Developers
- https://developers.google.com/android/images
- これがいわゆる「リカバリイメージ」でファクトリーリセットをかけたときに使用されるイメージ
- ※Pixel 6a は当初 Android12 だったが、Android 13 へのアップデートの際に bootloader の脆弱性も一緒に修正されたらしい。そのため一度 Android 13 にアップデートすると Android 12 に戻せなくなる
Full OTA Images for Nexus and Pixel Devices | Google Play services | Google Developers
- https://developers.google.com/android/ota
- これは Over the Air 、つまりネットワーク経由でアップデートするときにダウンロードされるファクトリイメージ。
A/B(シームレス)システム アップデート | Android オープンソース プロジェクト | Android Open Source Project
Magisk 公式:
Pixel6a + Magisk によるroot化解説記事:
【Magisk】発売翌日にPixel6aを早速Root化 入れたモジュールとか - ROM焼き試験場
Android13正式公開、ファーストインプレッション&Magisk導入【Pixel6a】 - ROM焼き試験場
Pixel 6にAndroid 13を強制的にインストール&Magisk導入(root化)する - りとらいん
ブートローダーとルート Pixel 6a のロックを解除する方法 - The Filibuster Blog
2. Proxy 設定
Android でProxyを設定するには、基本的には以下の通りWiFi設定から設定します。
- 「設定」アプリを開いて、
- →「ネットワークとインターネット」
- →「インターネット」
- → 接続中のWiFiアクセスポイント名の歯車アイコンをタップ
- → 詳細設定から「プロキシ」を「手動」で設定変更してProxyのIPアドレス/ポート番号を設定
実際の診断現場では、上記のWiFi設定を無視するアプリにもそれなりの頻度で遭遇します。 そのような場合、端末からの通信を丸ごと強制的に Proxy に流し込む以下のような Proxy 設定アプリを使います。
- ProxyDroid
- https://play.google.com/store/apps/details?id=org.proxydroid&hl=ja&gl=US&pli=1
- root化必須
- 内部的には iptables でルーティングテーブルを書き換えて、バンドルしている透過型TCP Proxy の redsocks を経由させることで素のHTTP(S)通信を Proxy 対応型の通信に変換しています。
- セキュリティエンジニア界隈でよく使われてる印象ですが、一方で、現場で使っている感覚としては時々調子が悪くなったり、redsocksが生成するHTTPのヘッダーが微妙なものがあって自家製 Proxy との相性が悪かったりするなど今一つな感じはあります。
- Super Proxy
- https://play.google.com/store/apps/details?id=com.scheler.superproxy&hl=ja&gl=US
- こちらは root化不要 です。(とはいえ、CA証明書のインストールでどちらにせよroot化は必要です。)
- Android のVPNの仕組みを活用しているらしく、Proxy設定した先に一種のHTTPトンネリングを張る動きになっていました。
- 現場で使ってる感覚としては、ProxyDroidでうまく動かなくても Super Proxy ではちゃんと動くケースがままあるように感じられ、筆者個人としてはこちらの方が安定感があります。
ProxyDroid も Super Proxy も、burpをProxy設定したケースのみ動作確認しています。 どちらも素のHTTP(S)通信を、ProxyDroid は redsocksで / Super Proxy はVPN機能を使ったHTTPトンネリングで burp などの Proxy に流し込んでいます。 それぞれの微妙な仕様/挙動により、細かいHTTPヘッダーやProxy接続するときの挙動にクセがあったりします。 burpは全般的に広く受け付けてくれるので「まずはburpで疎通確認」として作業していますが、OWASP ZAPやFiddlerなど他の MITM型Proxy でどうなるかは筆者も未検証です。
3. "Magisk Trust User Certs" モジュールによるCA証明書のインストール
Android 7 (Nougat) 以上になると、BurpなどMITM型Proxy が使用するCA証明書はシステムのCA証明書ストアに保存する必要があります。 これには root化端末で adb を使った linux shell コマンドの実行が必要で、具体的な手順については以下の記事で解説されています。
Configuring Burp Suite With Android Nougat - ropnop blog
*2
手順の中では openssl コマンドを使っており、全体的に面倒くさい手順となっています。 一度設定すれば長く使えるとはいえ、たまに Burp のCA証明書も入れ替わってるような感じもあるため、診断するたびにフレッシュなCA証明書をインストールするほうが安心です。*3 その都度この手順を流し直すのも手間ですが、これを自動化してくれる Magisk モジュールが公開されているので、そちらを使います。
Magisk Trust User Certs
以下は筆者の手元で Magisk でroot化した Pixel6a での大まかな手順紹介です。
Magisk Trust User Certs のインストール:
- https://github.com/NVISOsecurity/MagiskTrustUserCerts/releases より最新版の AlwaysTrustUserCerts.zip をPC側にダウンロードします。
- Magisk で root 化した Pixel6a をPCにUSB接続し、USBの接続用途で「ファイル転送/Android Audio」を選びエクスプローラから Pixel6a の内部共有ストレージにアクセスします。
- Pixel6a の内部共有ストレージに AlwaysTrustUserCerts.zip をコピーします。
- Pixel6a 側で Magisk を起動し、Magisk ホーム画面右下の「モジュール」→「ストレージからインストール」でコピーしてきた AlwaysTrustUserCerts.zip を選択します。
- インストール画面で特にエラーなど出ていなければ、右下の「再起動」をタップします。
Burp など MITM Proxy が使用するCA証明書のインストール:
- もう一度 Pixel6a をPCにUSB接続し、USBの接続用途で「ファイル転送/Android Audio」を選びエクスプローラから Pixel6a の内部共有ストレージにアクセスします。
- Pixel 6a の内部共有ストレージにCA証明書をコピーします。
- ※このとき、Burp の cacert.der の拡張子を “.crt” に変更しておきます。
- 「設定」アプリを起動して「セキュリティ」→「詳細設定」→「暗号化と認証情報」→「証明書のインストール」→「CA証明書」→「あなたのデータが公開されます」に対して「インストールする」→PIN番号入力→ファイル選択画面でハンバーガーメニューなどから「Pixel 6a」→ コピーしてきたCA証明書を選択します。
- 「暗号化と認証情報」まで戻り、「信頼できる認証情報」→「ユーザー」タブでインストールしたCA証明書情報が表示されることを確認します。
- Burpの場合は「PortSwigger」として表示されます。
- Pixel6a を再起動します。
- 「設定」アプリを起動して「セキュリティ」→「詳細設定」→「暗号化と認証情報」→「信頼できる認証情報」→「システム」タブにもインストールしたCA証明書が表示されればOKです。
インストールしたCA証明書の削除:
- 「設定」アプリを起動して「セキュリティ」→「詳細設定」→「暗号化と認証情報」→「ユーザー認証情報」からインストールしたCA証明書情報を長押しタップして「アンインストール」します。
- 同様に「暗号化と認証情報」→「信頼できる認証情報」→「ユーザー」タブからインストールしたCA証明書情報を長押しタップして「アンインストール」します。
- Pixel6a を再起動します。
- 「設定」アプリを起動して「セキュリティ」→「詳細設定」→「暗号化と認証情報」→「信頼できる認証情報」→「システム」タブからもインストールしたCA証明書が消えていればOKです。
4. "MagiskBypassCertificateTransparencyError" モジュールの導入
Android版 Chrome 99 以上では Certificate Transparency のチェックが導入されました。 これによりシステムレベルでインストールされたCA証明書についても Android 版 Chrome ではCTチェックの対象となります。
Certificate Transparency とは簡単に言うとサーバ証明書の発行履歴を透明化する試みであり、発行履歴をセキュアに公開することで不正な証明書発行を迅速に検知します。 ブラウザにおいてもサーバ証明書に埋め込まれたCT関連情報をチェックすることで、少なくとも発行履歴が監査可能な状態の証明書であるかを判断できます。
MITM型ProxyのCA証明書は一種の自己署名証明書であり、筆者の知る範囲ではCT関連情報がありません。
このため、MITM型Proxyを通して Android版 Chrome 99 以上で HTTPS アクセスすると以下のように ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
エラーが発生します。
これについては以下のblogで対処法も含め詳しく解説されています。
Android Chrome 99 expands Certificate Transparency, breaking all MitM dev tools | HTTP Toolkit
*4
対処法の手順としては証明書のSPKI fingerprint を抽出し、Chromeのコマンドラインオプション --ignore-certificate-errors-spki-list=$YOUR_SPKI_FINGERPRINT
に埋め込んだ上で、コマンドラインオプションを検知する設定ファイルに埋め込むという面倒な手順となっています。
これについても自動化してくれる Magisk モジュールが公開されていますので、こちらを使うことで簡単に対処できるようになります。
実際は Android版 Chrome 側の設定変更も必要です。 Magisk モジュールとして導入する手順が公式で紹介されています が、本記事ではスクリーンショットを交えて細かく解説していきます。
- Android の Chrome ブラウザで URL「
chrome://flags
」を開き、「Enable command line on non-rooted devices
」設定項目を探します。(虫眼鏡アイコンの検索ボックスに "enable command" まで入力すれば出てきました。)「Enable command line on non-rooted devices」設定項目 - 「
Enable command line on non-rooted devices
」の「Default」プルダウンをタップし、「Enable」に切り替えます。 - 「Enable」に切り替えたあと、Chrome画面の下部に「Relaunch」ボタンが表示されたらタップします。*5
- 再起動されたChromeでは、下部に以下のような警告メッセージが出ることがあります。利用者側で意図してフラグをONにしているので、この警告メッセージは無視して大丈夫です。
Chrome再起動後の警告メッセージ - Releaseページ より 「MagiskBypassCertificateTransparencyError.zip」 をPCにダウンロードします。
- AndroidをPCにUSB接続してファイル転送モードにし、PC上の「MagiskBypassCertificateTransparencyError.zip」をAndroid端末のストレージの直下にコピーします。
- Magisk を起動し、下部メニューより「モジュール」をタップします。
- モジュール一覧上部より「ストレージからインストール」をタップします。
- ストレージからのファイル選択画面が表示されたら、PC上からコピーした「MagiskBypassCertificateTransparencyError.zip」を選択してインストールします。
インストール成功時の画面例 - インストール成功画面の下部に「再起動」ボタンが表示されるので、タップして端末を再起動します。
- 再起動後、Android Chrome でもう一度 burp など proxy 通した状態でhttps にアクセスしてみて、正常に表示されればOKです。
httpsの正常表示画面例
まとめと感想
2022年末時点で Android における Proxy 設定のポイントと、Android版Chromeにおける NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
エラー の回避方法について紹介しました。
ポイントについてまとめます。
- Android端末はMagiskを使ってroot化します。
- WiFi の Proxy 設定を無視するアプリもあるので、ProxyDroid(root化必須) や Super Proxy などのProxy設定アプリも使うとよいです。
- MITM型Proxy のCA証明書は "Magisk Trust User Certs" を使ってインストールしましょう。
- Android版Chromeにおける
NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED
エラー は Chrome の設定と "MagiskBypassCertificateTransparencyError" を使って回避できます。
今回紹介してきた手順やポイントは、スマホアプリ開発を専業とする開発者の方にとっては日常的に情報収集するなどして容易にキャッチアップできるものと思います。
しかし「時々スマホアプリのHTTP(S)通信を診断する」ようなセキュリティエンジニアにとっては、触るたびに何かしら設定が壊れる・新しいトラブルに遭遇するという非常に悩ましい状況となっています。
2022年時点のスナップショットとして、そうしたセキュリティエンジニアの悩みを本記事が緩和できれば幸いです。
(とはいえ、また1年後・2年後にこの記事通りで動かせるかどうかわからない・・・これが、Android端末と付き合っていく上での目下最大の悩みです。)
*1:man-in-the-middle, "man"に限定しない表記としては "mallory" in the middle というのも考えられますが、使っているところは無いようです。
*2:Burp 公式の Android 用Proxy設定ガイド: https://portswigger.net/burp/documentation/desktop/mobile/config-android-device で紹介されています
*3:確証があるわけではないのですが、数ヶ月~1年くらいで、気がついたらburpのHTTPSで証明書エラーになるなどして、新たに最新のCA証明書をburpからexportしてimportし直すと解消されたりしますので、微妙に入れ替わってるんじゃないかな~と・・・
*4:こちらも Burp 公式の Android 用Proxy設定ガイド: https://portswigger.net/burp/documentation/desktop/mobile/config-android-device で紹介されています
*5:これをタップするか、表示されない場合はAndroidを再起動するなどして Chromeを完全に再起動しないと設定が反映されない・・・のだと、思われます。