AndroidエミュレータでHTTPS接続不可|「この接続ではプライバシーが保護されません」の原因と解決(Visual Studio 2022/.NET MAUI対応)

Visual Studio 2022 の Android エミュレータで HTTPS の API にだけつながらず、モバイル Chrome でも「この接続ではプライバシーが保護されません」と出て詰まる――この現象は、ほぼ例外なく“証明書の信頼”と“エミュレータ特有のネットワーク”が原因です。この記事では、最短で復旧させる手順から、根本理解・恒久対策・落とし穴の回避まで、現場でそのまま使えるレベルで詳しく解説します。

目次

現象と前提の整理

  • Visual Studio 2022 付属の Android エミュレータで、アプリが自社 API(HTTPS)へ接続できない。
  • エミュレータ内の Chrome で同じ URL を開いても、「この接続ではプライバシーが保護されません(NET::ERR_CERT_AUTHORITY_INVALID など)」が表示され閲覧不可。
  • 開発 PC(ホスト)のブラウザでは正常にアクセスできるため、ホスト側ネットワークは正常。

結論から言うと、エミュレータの OS があなたの開発用証明書(CA またはサーバー証明書)を信頼していない、あるいはエミュレータからの到達先(ホストの localhost 相当)を誤っていることが原因です。以降の手順で確実に解消できます。

最短解決フロー(まずはこれだけ)

  1. 接続先 URL を 10.0.2.2 へ修正(エミュレータからホストの localhost に到達するための特別アドレス)。例:https://10.0.2.2:7043/
  2. エミュレータに“信頼できる CA 証明書”をインポート(自己署名や社内 CA を使っているなら必須)。CA を用意できない場合は、開発時のみ chrome://flags/#allow-insecure-localhost を使う。
  3. アプリが Android 7.0+ で「ユーザー追加 CA」を既定で信頼しない仕様に該当する場合、debug ビルドの network_security_config でユーザー CA を明示的に許可する。
  4. それでもダメなら、日付時刻ズレ・証明書チェーン欠落・SAN/ドメイン不一致・プロキシ/MITM・TLS バージョン不一致を順に点検。

原因を一枚でつかむ:対処一覧

対処手順 / 補足効果注意点
① エミュレータへ開発用CA証明書をインストール1) 開発環境で使っている CA の証明書(.crt/.pem)を用意
2) エミュレータへ転送(ドラッグ&ドロップ or adb push rootCA.crt /sdcard/Download/)
3) Android 設定 → セキュリティ → 暗号化と認証情報 → CA 証明書をインストール
4) 再起動後、Chrome とアプリを再試行
根本解決。以後その CA で署名した全証明書を信頼。インポートできるのは CA:TRUE な証明書のみ。単体のサーバー証明書は「CA 証明書」として登録できない。
② Chrome で一時的に検証緩和(開発限定)chrome://flags/#allow-insecure-localhost を Enabled。
localhost に対する無効証明書を許容(テスト目的の暫定策)。
動作確認が即できる。本番・QA 禁止。主に https://localhost を対象にした挙動で、10.0.2.2 には効かないことがある。
③ HTTP に切替(どうしても HTTPS が整わない場合)Android 9+ は既定で HTTP をブロック。
network_security_config.xml の cleartextTrafficPermitted="true" で許可、または対象ドメインのみ許容。
併せて Manifest に android:usesCleartextTraffic="true" を設定。
証明書問題を回避して接続可。開発限定。本番は必ず HTTPS。
④ モバイル OS の証明書要件を理解アプリは証明書検証を無効化できない。サーバー証明書はグローバル CA か、手動登録済み CA で署名。設計段階で迷わない。アプリでのピン留め(証明書ピンニング)を有効にしている場合は別途更新が必要。
⑤ 追加トラブルシューティング時刻ズレ、ブラウザキャッシュ、Wi‑Fi/プロキシ環境、セキュリティアプリの干渉、SAN/ドメイン不一致、チェーン欠落、SNI/IP アクセスの矛盾を順に確認。原因の切り分けが早い。エミュレータの「データを消去」や OS 更新でユーザー CA が消える場合あり。

“エミュレータ ↔ ホスト”の正しい到達先:10.0.2.2

標準 Android エミュレータからホストの localhost に接続するには、10.0.2.2 を使います。例えば ASP.NET Core 開発サーバーがホストで https://localhost:7043/ なら、エミュレータからは https://10.0.2.2:7043/ です。

  • ホストのファイアウォールで該当ポート(例:7043)が開いているか確認。
  • IPv6 や VPN を併用していると名前解決・経路で迷子になることがあるため、一旦切って検証。

最重要:エミュレータに「信頼できる CA」を入れる(恒久策)

自己署名のサーバー証明書を直接インポートしても、Android の「CA 証明書」としては登録できません(CA:TRUE ではないため)。ルート CA か中間 CAをエミュレータに登録し、その CA が署名したサーバー証明書を使うのが正攻法です。

CA を用意する最短ルート(mkcert)

  1. ホストに mkcert を導入し、mkcert -install でローカル CA を作成。
  2. API 用の証明書を発行:例)mkcert api.dev.local 10.0.2.2 localhost
  3. 生成物(.pem / .key)をサーバーに設定。
  4. エミュレータには mkcert のルート CA(例:rootCA.pem)をインポートする。

mkcert の CA ファイルは通常ユーザーディレクトリ配下(例:%LOCALAPPDATA%\mkcert\rootCA.pem)にあります。

ASP.NET Core / .NET MAUI と dev-certs

dotnet dev-certs https --trust は、Windows/macOS のローカル証明書ストアへ「開発者用(localhost)証明書」を登録するだけで、Android エミュレータには一切反映されません。エミュレータ側には CA を入れる必要があります。既存の localhost.pfx をエミュレータへ入れても CA ではないため、Chrome のエラーは解消しません。

証明書の形式変換(OpenSSL)

エミュレータは .crt/.pem などの X.509 をインポートできます。PFX/P12 の場合は以下のように変換します。

# PFX → サーバー証明書(PEM)
openssl pkcs12 -in server.pfx -clcerts -nokeys -out server.crt

# PFX → 秘密鍵(開発サーバー側で使用;エミュレータへは不要)

openssl pkcs12 -in server.pfx -nocerts -nodes -out server.key

# ルートCA(PEM)を DER(CRT)へ

openssl x509 -in rootCA.pem -outform DER -out rootCA.crt 

エミュレータにインポートするのは rootCA.crt(CA)側です。

エミュレータへのインポート手順(UI)

  1. エミュレータを起動し、CA ファイルをドラッグ&ドロップ、または adb push rootCA.crt /sdcard/Download/。
  2. Android の「設定」→「セキュリティ」→「暗号化と認証情報」→「SD カードからインストール」を開く(名称は OS により若干異なる)。
  3. 種別として 「CA 証明書」を選んで rootCA.crt を選択。
  4. インポート後、エミュレータを再起動。

「ユーザー証明書」「VPN とアプリ」などに入れても サーバー証明書の信頼は広がりません。必ず CA 証明書として登録してください。

(発展)システム CA への配置

アプリが「ユーザー追加 CA を信頼しない」場合に備え、エミュレータのシステム CA ストアへ配置する手もあります(開発機限定・自己責任)。Google 純正エミュレータは adb root と adb remount に対応することが多く、以下のように配置できます。

adb root
adb remount
# ハッシュ名へリネーム(OpenSSL の c_rehash 相当)
# 例:ファイル名を 9a5ba575.0 のようにして配置
adb push rootCA.crt /system/etc/security/cacerts/9a5ba575.0
adb shell chmod 644 /system/etc/security/cacerts/9a5ba575.0
adb reboot

これで「ユーザー CA ではなくシステム CA」として認識され、アプリ既定の信頼にも乗ります。ただし OS アップデートやエミュレータの「データを消去」で失われる点には注意。

Android 7.0 以降:ユーザー CA をアプリが既定で信頼しない問題

Android 7.0(API 24)以降、アプリはユーザー追加 CA を既定で信頼しません。Chrome はユーザー CA を使いますが、あなたのアプリ(OkHttp/HttpClient 等)は使わない可能性があります。debug ビルドに限り network_security_config.xml でユーザー CA を許可しましょう。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <debug-overrides>
    <trust-anchors>
      <certificates src="user"/>  <!-- ユーザー追加 CA を信頼 -->
    </trust-anchors>
  </debug-overrides>






 

AndroidManifest.xml(application 要素)でこの設定を参照します。

&lt;application
    android:name=".App"
    android:networkSecurityConfig="@xml/network_security_config"
    android:usesCleartextTraffic="false"
    ... /&gt;

本番ビルドでは ユーザー CA を許可しない設定に戻すか、グローバルに信頼される公的 CA で署名した証明書を使います。

Chrome の暫定回避:allow-insecure-localhost

開発中にブラウザだけでも動作を見たいとき、エミュレータの Chrome で chrome://flags/#allow-insecure-localhost を Enabled にすると、localhost 宛の無効証明書を一時的に許容します。ただし次の制約を理解しておきましょう。

  • 対象は 原則 localhost。10.0.2.2 には効かない挙動がある。
  • テスト目的の暫定策。本番・QA では禁止。
  • アプリ側の HTTP クライアントには影響しない。

どうしても HTTPS が整わないときの HTTP 許可(開発限定)

Android 9(API 28)以降は既定で HTTP がブロックされます。開発限定で HTTP 通信を許すには、次のように設定します。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <base-config cleartextTrafficPermitted="true">
    <trust-anchors>
      <certificates src="system"/>
      <certificates src="user"/> <!-- 必要なら -->
    </trust-anchors>
  </base-config>



10.0.2.2

 

Manifest:

&lt;application
    android:usesCleartextTraffic="true"
    android:networkSecurityConfig="@xml/network_security_config" /&gt;

繰り返しになりますが、運用環境では必ず HTTPSにしてください。

追加トラブルシューティング ― 原因別チェックリスト

症状確認ポイント解決のヒント
NET::ERR_CERT_AUTHORITY_INVALIDCA が未登録/間違いエミュレータへ CA 証明書をインポート。サーバー証明書のインポートでは直らない。
NET::ERR_CERT_COMMON_NAME_INVALIDSAN/ドメイン不一致証明書の SAN に 10.0.2.2、localhost、使用ドメインを含め再発行。
NET::ERR_CERT_DATE_INVALIDエミュレータの時刻ズレ設定 → 日付と時刻 → 自動を ON/OFF して再取得。再起動。
チェーン不完全中間 CA 未送出サーバーに中間証明書を連結(fullchain.pem の提供)。
アプリだけ失敗、Chrome は成功Android 7+ のユーザー CA 非信頼network_security_config の <debug-overrides> で user CA を許可。
IP 直指定で失敗SNI/ホスト名不一致ドメインでアクセスするか、証明書に IP を SAN 追加。
会社のプロキシでのみ失敗SSL 検査(MITM)プロキシのルート CA をエミュレータへ入れるか、検査を無効化(社内手続き)。

よくある落とし穴と回避策

  • 「VPN とアプリ」にサーバー証明書を入れても直らない:そこはクライアント認証用。信頼の拡張は CA 証明書で行う。
  • エミュレータの「データを消去」や OS 更新でユーザー CA が消える:スナップショット運用や自動スクリプト(adb push → 設定)で再現可能に。
  • ASP.NET Core の開発証明書(localhost.pfx)をそのまま配ろうとする:CA ではないのでエミュレータの Chrome 警告は消えない。mkcert などで CA を作成し、サーバー証明書はその CA で再発行。
  • OkHttp/HttpClient の検証無効化をコードでやる:セキュリティ観点で非推奨。network_security_config と CA 管理で解決を。

具体手順:ASP.NET Core(Kestrel)× .NET MAUI の例

  1. mkcert を導入し、mkcert -install(ホストに CA を作成)。
  2. 開発 API 用に証明書作成:mkcert localhost 10.0.2.2 api.dev.local
  3. Kestrel の appsettings.Development.json で証明書を指すか、起動引数で --cert --key を指定。
  4. エミュレータに rootCA.crt を「CA 証明書」でインポート、再起動。
  5. アプリの network_security_config.xml に <debug-overrides><certificates src="user"/> を記述し、Manifest で参照。
  6. アプリの接続先を https://10.0.2.2:<ポート>/ に設定。

診断に使えるコマンド集

# 証明書チェーンと SNI の確認
openssl s_client -connect 10.0.2.2:7043 -servername localhost -showcerts

# エミュレータへファイル転送

adb push rootCA.crt /sdcard/Download/

# エミュレータの日時確認(shell)

adb shell date

# エミュレータのプロキシ設定をリセット(必要に応じて)

adb shell settings put global http_proxy :0 

CORS と TLS を切り分ける

「TLS 警告が消えたが API が 4xx/5xx」で止まる場合、原因は CORS(オリジン制約)であることが少なくありません。まず TLS が完全に確立しているか(Chrome のアドレスバーが安全表示か、アプリ側で SSL 例外が発生していないか)を確認し、TLS が問題ないなら CORS ポリシーを見直します。

セキュリティと運用のベストプラクティス

  • 開発・検証・本番で証明書を分離し、秘密鍵の取り扱いを厳格に。
  • mkcert の CA をチームで共有する場合はアクセス制御と鍵の保護を徹底。
  • ピンニングを採用するなら、CA/証明書更新の手順を CI/CD に組み込み、失効や更新時のリリース手順を文書化。
  • エミュレータの更新やクリーンアップで CA が消える前提で再登録スクリプトを用意。

トラブルを未然に防ぐチェックシート

項目Yes/No備考
接続先は 10.0.2.2 を使用している□ホストの localhost を指す特別アドレス
エミュレータに CA 証明書をインポート済み□CA:TRUE の証明書であること
中間 CA を含むフルチェーンをサーバーが返している□OpenSSL で確認
証明書の SAN に使用ホスト(10.0.2.2/ドメイン)が含まれる□CN だけでは不十分
アプリの network_security_config を debug で調整□ユーザー CA を許可
エミュレータの日時が正しい□自動取得のオン/オフで再同期
プロキシ/MITM 製品の影響を排除□社内 CA の登録 or 検査無効化

FAQ

Q. サーバー証明書(localhost.pfx)はエミュレータで使えますか? A. いいえ。Android の「CA 証明書」は CA しか登録できません。CA を登録 → その CA で署名したサーバー証明書を使うのが正解です。 Q. Chrome で手動「続行」できないのはなぜ? A. HSTS など厳格なポリシーや重大な検証エラーでは回避操作が出ないことがあります。CA の登録で根本から直すべきです。 Q. 10.0.2.2 以外に方法は? A. ADB のリバースポート(adb reverse tcp:7043 tcp:7043)なども使えます。構成を増やすほど混乱しやすいので、まずは 10.0.2.2 を基本に。 Q. エミュレータを入れ替えたら再発しました。 A. 新しい AVD には CA が入っていません。セットアップ手順(CA インポート)を再実施してください。

まとめ

Android エミュレータで HTTPS API に接続できず「この接続ではプライバシーが保護されません」となる主因は、エミュレータがあなたの開発用証明書を信頼していないことと、エミュレータ固有のホスト到達先(10.0.2.2)を誤っていることです。CA をエミュレータに登録し、debug の network_security_config でユーザー CA を許可、接続先は 10.0.2.2 に統一――この 3 点を押さえれば、エミュレータでも安全に HTTPS で API に接続できるようになります。開発中の暫定回避(Chrome フラグや HTTP 許可)はあくまで短期用途とし、最終的には CA と証明書の正しい管理で本質的に解決しましょう。


付録:実施手順を最小コストで自動化する

新規 AVD を作るたびに CA を入れ直すのは面倒です。次の方針で自動化すると楽になります。

  1. CA の単一保管:リポジトリに「開発用 CA 証明書(公開鍵のみ)」を格納。
  2. スクリプト化:adb push → インテント呼び出しで認証情報画面を開く(手動タップのみ最後に必要)。
  3. mkcert の再発行コマンド:対象 SAN(localhost、10.0.2.2、開発用ドメイン)を README に明記。
  4. AVD スナップショット:CA 登録済み状態でスナップショットを取り、以後そこから起動。

付録:チェックリスト(コピー&使い回し用)

[ ] エミュレータからの到達先は https://10.0.2.2:&lt;PORT&gt;/ に統一
[ ] mkcert で開発用 CA を作成し、サーバー証明書はその CA で再発行
[ ] エミュレータに CA を「CA 証明書」としてインポート済み
[ ] Android 7+ 対策:debug の network_security_config で user CA を許可
[ ] サーバーは中間 CA を含むフルチェーンを返す(fullchain)
[ ] SAN に 10.0.2.2 / localhost / 開発ドメインを含める
[ ] エミュレータの時刻は自動同期で正しい
[ ] プロキシ/MITM/セキュリティアプリによる干渉なし
[ ] (必要時のみ)HTTP 許可は debug に限定、運用では HTTPS 固定

補足情報(知っておくと役立つポイント)

  • ローカルホストのアドレス:エミュレータからホストの localhost へは http(s)://10.0.2.2:<ポート> を使用。
  • 自己署名証明書を頻繁に更新する場合の効率化:mkcert などでローカル CA を作成し、エミュレータに一度だけ CA 証明書を登録すれば、その CA で発行したすべてのドメイン証明書が自動的に信頼される。
  • .NET MAUI / ASP.NET Core を併用している場合:dotnet dev-certs https --trust はホスト OS のローカルストア登録のみ。エミュレータ向けには本記事の手順で別途 CA をインポート。

アクションプラン(今すぐやる)

  1. mkcert -install で CA 作成 → サーバー証明書を再発行。
  2. エミュレータに rootCA.crt を「CA 証明書」で登録、再起動。
  3. 接続先を https://10.0.2.2:<PORT>/ に統一。
  4. debug の network_security_config で <certificates src="user"/> を許可。
  5. OpenSSL でチェーンと SAN を最終確認。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次