Help us understand the problem. What is going on with this article?

Unityで作成したAndroidアプリのhttp/https通信をキャプチャする

概要

Androidアプリの通信がどのように見えるのか気になったので、パケットキャプチャして通信内容を見る方法について調べてみた。思いのほか大変だったので情報をまとめておく。

筆者の環境はPCがWin10でスマホがAndroid8.1。

筆者はUnityに関して素人で、http/https通信についてもよく分かってない人間なので注意。

1.Unityで適当に通信するアプリを作る

通信するクラスを適当に作成。
テストがしたいだけなので、なんか良い感じのサーバないかな?と思ったらhttpbinなる便利なサイトを発見。使わせて頂きます。圧倒的感謝。使い方その他は以下のサイト様が分かりやすいです。
https://www.softantenna.com/wp/review/httpbin/

WebRequestTest.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class WebRequestTest : MonoBehaviour
{
    public string URL;
    [SerializeField] private Dropdown dropdown;

    public IEnumerator WwwRequestTest(string url)
    {
        WWW www = new WWW(url);
        yield return www;
        Debug.Log(www.text);
    }

    public IEnumerator UnityWebRequestTest(string url)
    {
        using (UnityWebRequest request = UnityWebRequest.Get(this.URL))
        {
            yield return request.SendWebRequest();
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.Log(request.error);
            }
            else
            {
                Debug.Log(request.downloadHandler.text);
            }
        }
    }

    public void HttpWebRequestTest(string url)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            Debug.Log("Proxy.Credentials: " + request.Proxy.Credentials);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream stream = response.GetResponseStream();
            string webContext = new StreamReader(stream).ReadToEnd();
            Debug.Log(webContext);

        }
        catch (WebException webException)
        {
            var ex = webException as Exception;
            while (ex != null)
            {
                Debug.Log(ex.ToString());
                ex = ex.InnerException;
            }
        }
    }

    public void OnWWWButtonClicked()
    {
        Debug.Log("OnWWWButtonClicked");
        Debug.Log(this.URL);

        StartCoroutine("WwwRequestTest", this.URL);
    }

    public void OnUnityWebRequestButtonClicked()
    {
        Debug.Log("OnUnityWebRequestButtonClicked");
        Debug.Log(this.URL);

        StartCoroutine("UnityWebRequestTest", this.URL);
    }

    public void OnHttpWebRequestButtonClicked()
    {
        Debug.Log("OnHttpWebRequestButtonClicked");
        Debug.Log(this.URL);

        this.HttpWebRequestTest(this.URL);
    }

    public void OnURLChanged()
    {
        var keyMap = new Dictionary<int, string>();
        keyMap.Add(0, "http://httpbin.org/ip");
        keyMap.Add(1, "https://httpbin.org/ip");

        this.URL = keyMap[this.dropdown.value];
    }
}

以上のスクリプトを適当なGameObjectに追加して、適当にボタンとurlを変更するドロップダウンメニューを作成する。

android_http_test.png

エディタ上で動作することを確認したあと、apkをビルドして実機にインストールする。

通信ができているかどうかの確認はDebug.logの出力で確認できる。Android実機で確認する場合のadbコマンドは以下。

adb logcat | findstr -i unity

2 パケットキャプチャする方法を調べる

Androidでパケットキャプチャする方法を調べてみたら結構いろんな方法がでてきた。

2-1 tPacketCapture

まず一番手軽なのはtPacketCaptureを使う方法。

分かりやすい紹介記事様。
https://www.teradas.net/archives/17033/

tpacketcap.png

このアプリを使って先程作成したアプリの通信をキャプチャしてみたところ、暗号化されていないhttp通信はデータの中身まで見れたが、暗号化されているhttps通信はデータの中身までは見れなかった。
公式サイトには以下の記述がある

tpacketcap.png

原理的に通信の中身までは見れないらしい。https通信は暗号化されているので復号する必要があるが、この方法だとできない。

2-2 Fiddler

android_http_test.png

ということでhttps通信のデータの中身まで見る方法を調べてみたところFiddlerというツールを使えば見れるらしい。Fiddlerの他にも同類のツールはいろいろある様子。

導入方法その他は以下のサイト様の記事が分かりやすい。
https://amimilab.com/2016/08/14/post-183/

Fiddlerで立てたプロキシサーバ経由で通信することで、Fiddler上で通信の中身を全部みれるようになるらしい。
だがしかしBat、上記のサイト様を参考にFiddlerを試してみても、https通信はキャプチャできなかった。調べてみたところAndroidのca証明書に関する仕様が変わったのが原因らしい。

Androidの通信まわりの仕様変更

Android7で特別に設定されていない限り、カスタムされたca証明書を無視する仕様になったらしく、Fiddlerが生成したca証明書をAndroid端末にインストールしてもこの証明書は無視されてしまうようだ。アプリ側で使用するca証明書を明示する必要性があるらしい。

android_http_test.png

https://developer.android.com/about/versions/nougat/android-7.0#default_trusted_ca

余談だがAndroid9ではデフォルトでhttp通信ができないようになっているらしいので、Android9以上の端末を使用する場合は注意が必要です。
https://developer.android.com/about/versions/pie/android-9.0-changes-28?hl=ja#apache-p

カスタムca証明書を利用して通信するように設定する

Android公式のドキュメントを参照するとAndroidManifest.xmlのapplicationの項目に networkSecurityConfigというプロパティ?を記述して、さらに設定ファイルを追加する必要があるらしい。

UnityでapkをビルドするときはAndroidManifest.xmlをUnity先生が勝手に良い感じに作成してくれているが、これを編集する必要があるようだ。これに関しては以下のサイト様が詳しい。
https://blog.wizaman.net/archives/1026

Assets/Plugins/Androidディレクトリ配下にAndroidManifest.xmlを追加するとビルドするときにUnity先生が良い感じにマージしてくれるらしい。雛形のAndroidManifest.xmlの入手方法は、公式によるとapkをビルド後にAndroidManifest.xmlがキャッシュされているらしいのでこれをコピペして使うのが手軽かもしれない。場所はTemp/StagingArea/AndroidManifest.xml

自分はビルドしたapkファイルをapk_toolでデコンパイルして入手した。

Assets/Plugins/Androidディレクトリ配下にAndroidManifest.xmlをコピペしたらこれを編集する。application のところにandroid:networkSecurityConfig="@xml/network_security_config"と記述する。

        <application android:networkSecurityConfig="@xml/network_security_config" >
        </application>    

https://developer.android.com/training/articles/security-config?hl=ja#manifest

次にAssets/Plugins/Android/res/xmlディレクトリを作って配下に適当なテキストエディタかなんかでnetwork_security_config.xmlファイルを作成する。内容は以下。

   <network-security-config>
        <base-config>
            <trust-anchors>
                <certificates src="system"/>
                <certificates src="user"/>
                <certificates src="@raw/fiddlerroot"/>
            </trust-anchors>
        </base-config>
    </network-security-config>

ちなみにこのnetwork_security_config.xmlファイルについてググってると<certificates src="user"/>だけでイケるっていう情報があったが自分はだめだった。上記のようにca証明書を直接指定してやったらイケた。

ということで、次にFiddlerがhttp://ipv4.fiddler:8888/で生成してくれるca証明書をdlしてAssets/Plugins/Android/res/raw/ 配下に追加する。このときca証明書はFiddlerRootっていう名前になっていると思うが、AndroidManifestでは大文字は使えないので、リネームする必要があることに注意。自分は適当にfiddlerrootに変更した。

以上を設定できたらUnityでapkをビルドしてAndroid端末にインストールする。あとはFiddler上でhttp/https通信の中身を全部見れるようになる。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away