モバイルファースト時代のネットワークレイヤデバッグ手法

こんにちは。インフラストラクチャー部 セキュリティグループの星 (@kani_b) です。
クックパッドでは主に "セキュリティ" か "AWS" というタグのつきそうな業務全般を担当しています。

ここ数年、クックパッドではいわゆるネイティブアプリの開発が非常に盛んです。
私達インフラストラクチャー部はネイティブアプリの直接の開発者ではありませんが、開発が円滑に進むように色々なレイヤでそのお手伝いをしています。

PC 向けサービス開発と比較して、スマートフォン向け、特にネイティブアプリにおいては、何かトラブルがあった際に どこで何が起きているか、そのデバッグを行うことが若干難しいと感じています。 今回はいわゆる jailbreak や root 化をせず、ネットワークのレイヤからデバッグを行う方法についていくつかご紹介します。

HTTP プロキシによるキャプチャ

まずは HTTP プロキシを利用してリクエスト/レスポンスのキャプチャを行う方法です。 アプリが行っている通信が HTTP/HTTPS だけで、対象のスマートフォンに自由にアクセスでき、 HTTP レイヤで様子を伺うことができれば良い場合はこちらを使います。

以下のようなソフトウェアが使えます。

  • Charles Proxy
    • シェアウェア。GUI で操作できる
  • Burp Proxy
    • Free 版と Professional 版がある。GUI で操作可能。脆弱性検査などにも多く利用されている (主に Professional 版)
  • Fiddler
    • Burp と同じく、脆弱性検査などにも利用されているプロキシ。無料ソフトウェアとして公開されている
  • mitmproxy
    • OSS。Python で実装されている。ターミナルから使う

これらのツールの使い方は基本的には共通しています。起動すると PC に HTTP Proxy を作成してくれるので、 開発用のスマートフォンのネットワーク設定を変更し、起動した Proxy を経由するようにするだけです。 PC が接続されているネットワークと同じネットワークに接続して設定するのが楽で良いでしょう。 他のソフトウェアにも様々な機能がありますが、デバッグ用途であれば大半のケースで mitmproxy が使えると思います。

以前のバージョンの mitmproxy で HTTPS 通信をキャプチャするためには、初回起動時に生成された証明書一式を 何らかの手段でスマートフォンに転送して…という設定を行う必要があったのですが、 現在はプロキシの設定をした状態で mitm.it にアクセスすると証明書をダウンロードできます。 (上記リンクを踏むとわかりますが、プロキシを通さないと正しく設定ができていないことがわかります)

これで、HTTP/HTTPS 通信をキャプチャする用意ができたので、スマートフォン側でプロキシの設定をするだけです。 試しにクックパッドアプリ開発環境の通信をキャプチャしてみると以下の画面のように見えます。 f:id:kani_b:20150528164909p:plain

任意のリクエスト/レスポンスについて詳細 (header, body, etc) を確認することもできます。 また、リクエスト/レスポンスのリプレイや書き換えも可能なので、 例えばクライアント、サーバ共に細工したリクエストやネットワーク環境悪化による再送などが悪影響を及ぼさないか調査することも可能です。

パケットキャプチャ

HTTP プロキシを使うとだいたいのケースでデバッグを行うことが可能ですが、 以下のような場合は HTTP レイヤではなく IP レイヤでキャプチャを行う必要があります。

  • キャリア回線を使っている時の通信をそのまま解析したい
  • (DNS|SSL/TLS|その他 HTTP 以外のプロトコル)で行われている通信を確認したい
    • 例えば TLS handshake で決まった CipherSuite の確認など

iOS の場合

iOS と Mac を利用している場合、Remote Virtual Interface (RVI) が使えるようになっています。 RVI は Apple のドキュメントにも記載されていますが、USB 接続した iOS デバイスが行う通信を Mac 側にミラーしてくれるインタフェースです。 通信を Mac 経由で行うのではなく、あくまで iOS デバイスのメインネットワークインタフェース (4G や Wi-Fi) が行っている通信のコピーが Mac に流れてきているだけですので、自然な形でキャプチャを行うことができます。 RVI のセットアップも、Mac と iOS デバイスを USB で接続し、対象の iOS デバイスの UUID を調べたら以下のように RVI デバイスを作成します。

$ rvictl -s xxxxxxxxxxxxxxxxxxxxxx (デバイスの UUID)

この状態で ifconfig を見ると rvi0 というインタフェースが作成されています。

$ ifconfig rvi0
rvi0: flags=3005<UP,DEBUG,LINK0,LINK1> mtu 0

このインタフェースは他のネットワークインタフェースと同様に扱えますので、tcpdump や Wireshark など お好みのネットワークアナライザでキャプチャや解析を行うことが可能です。 一例として、Wireshark を使えば GUI 上で簡単に解析を行うことができます。 f:id:kani_b:20150528164934p:plain

Android の場合

Android は root 化なしに RVI のようなものを使う手段がないため、 tPacketCapture などキャプチャ用 Android アプリを利用するか、 Android が利用するネットワークの経路上 (例えば PC を Wi-Fi AP にしてそこに接続する) でキャプチャを行う必要があります。
他に良いキャプチャ方法をご存知の方がいたら是非教えてください!

デバッグできるレイヤを増やす

スマートフォンアプリに問題が起こった際、上記のようにネットワークレイヤからも調査できるようにしておくと 調査の幅が広がります。
例えば、筆者は以下のようなことをこれまで紹介したような方法で調査していました。

  • アプリの不具合により、HTTP ヘッダに予期していないバイト列が含まれリクエストに失敗する現象
  • アプリが利用する特定のホストに対して名前解決が行われなくなる現象
  • 特定のアプリ/端末が HTTPS 接続で利用する CipherSuite
  • API エンドポイントに不正な文字列やリプレイされたリクエストを送出した時の挙動

まとめ

この記事では、主にネットワークのレイヤから、スマートフォンアプリのデバッグを行う手法について解説しました。 ここで紹介した手法はアプリ開発者に限らず、サーバ側の開発・運用に携わる方も覚えておいて損はないと思います。
クックパッドではエンジニアの役割によらず、それぞれの得意とするレイヤで協力しながら調査を行うことがよくあります。
色々な視点から、楽しいデバッグライフを送りましょう。