iOS / Android のアプリの署名について調べてみた

最近スマートフォン向けの開発をしているのですが、アプリの配布などを行う際のセキュリティの仕組みがよくわからなくてモヤモヤしていました。特に iOS の方はプロビショニングプロファイルやら証明書やらが大量にあり、何をどう管理すればいいのかがよくわかりにくいです。

というわけで、アプリケーションを配布する際の署名やその他のセキュリティの基本的な仕組みを調べたので、それを整理してみました。原始的な配布方法から複雑な iOS の配布方法までを段階的に書いています。

対策なし

f:id:wm3:20150217030231p:plain

まずはもっとも簡単な配布方法。署名などの難しいことは一切何もしない方法です。昔ながらの PC 向けのアプリの配布方法です。

考察

この方法での配布は、USBメモリで直接渡すならともかく、インターネット経由で不特定多数に配布する場合等だとあまり安全とは言えないでしょう。 メール配布などであればなりすまし放題です。フィッシング詐欺なども簡単に起こってしまいそうです。

この方法でのアプリの実行は iOS でも Android でも基本できないと思います。

開発者による署名

f:id:wm3:20150217030232p:plain

より安全にアプリを配布する方法として、アプリのファイルに公開鍵/秘密鍵のペアを使って署名を行う事が行われています。 iOSAndroid では開発者自身による署名が無いアプリは受け入れてくれません。

アプリに開発者による署名を付加する事により、アップグレードが安全になります。新しいアプリが同じ署名で行われていれば同じ開発者による開発である事が保証できるためです(もちろん秘密鍵はきちんと管理されている必要があります)。

考察

何もしないよりはだいぶ安全ですが、開発者による署名だけでは十分ではなさそうです。特に、オリジナルの開発者自身に悪意があった場合、安全を保障する事はできません。マルウェアスパイウェアを防ぐ助けにはならなそうです。

そのためか、 Androide でも iOS でも、署名だけでは基本的には実行できません。 Android では「提供元不明のアプリ」のインスールを許可する設定をする事で実行できるようになります。iOS では Jailbreak しない限り実行できません。

補足 (iOS)

補足 (Android)

  • 署名は Android 独自のものではなく、 JAR にある署名の仕組みを使用しています。
  • Java 付属の keytool や jarsigner でもキーペアの管理や署名が行えますが、まっとうな開発者は Gradle や Android Studio を使う模様です。
  • Android の署名に関しては、以下が参考になります

利用する機能や使用条件の宣言

f:id:wm3:20150217030233p:plain

iOS でも Android でも、インストールさえできれば端末の全機能が自由に使える…という風にはなっていません。個人情報の取得や外部サービスとの連携などの機能はユーザーが明示的に許可しないと実行できないようになっています。

Android の場合、使用する機能をアプリ内のマニフェストファイル (AndroidManifest.xml) に記載させ、どのような機能を使うかをユーザーがわかるようにしています。こうすれば、例えば全く必要もなさそうなのに連絡帳にアクセスするようなマルウェアは、実行前に認識できます。

考察

マニフェストに記載する機能の粒度は比較的大雑把です。細かい検証はできませんので、これだけで安全という判断はできません。

また、プラットフォームのベンダー(Google)としては、配布の許可をコントロールしたいでしょう。

補足 (iOS)

  • iOS の場合、機能の許可はマニフェストを経由して行いません。代わりに、該当する API を呼び出す際に、承認を求めるダイアログが表示されます。
  • iOS のプロビショニングプロファイルは「実行の条件を記述して利用を制限させる」という意味ではマニフェストに似ています。しかしプロビショニングプロファイルの目的は使用する機能の制限というよりは、配布の制限という意味合いが強そうです。

ストアによる審査

f:id:wm3:20150217030234p:plain

AndroidiOS でも、アプリの安全性を保障する最終段階はプラットフォームベンダー(もしくは信頼できるサードパーティ)による審査を通した配布方法に制限することです。ローテクですが、誰にでもわかりやすい手法です。

考察 (審査以外の手法も併用する理由)

この方法はもっとも安全そうです。署名やマニフェストによって保護しているセキュリティの機能のほとんどは、流通経路の制限と審査だけで実現できそうです。

しかし実際にはストアによる管理だけでなく、署名やマニフェストを併用されています。審査以外の方法が適用されている理由としてあげられそうなものを整理してみました。

  • マニフェストが必要な理由
    • プライバシー保護の許容範囲などは個人の嗜好によるので、個人で判断してもらう必要がある。
    • 使用する機能をユーザーに承認させる仕組みがあればマニフェストである必要は無い
  • 開発者による署名が必要な理由
    • Android はオープンなプラットフォームなので、ストアを経由しない配布方法を提供したい
    • iOS の場合はプロビショニングプロファイルの正当性の検証に使う(後述)

ちなみに、プラットフォームベンダーによる配布のコントロールができるというのも、他の手法にはない特徴なのではないかと思います。

ストアを通さない検証

f:id:wm3:20150217030235p:plain

iOS のアプリを配布する際には、やたらと面倒なプロビショニングプロファイルという物を使います。プロビショニングプロファイルを使うことで、ストアなどで流通経路に制限をかけることをせずに、配布に制限をかけることができます。

プロビショニングプロファイルの仕組みを書いてみます。一部憶測が入っていますのでご了承下さい…。

仕組み (パッケージング時)

開発者はプロビショニングプロファイルをプログラムと一緒にパッケージングし、署名を行った上で配布します。

プロビショニングプロファイルには、Apple によって署名された許可証のようなものになっています。契約内容は例えば以下の通りです。

開発用のプロビショニングプロファイルの場合

この証明書に添付された署名(公開鍵)がされている
XXXという ID のアプリは
YYY と ZZZ のデバイスによって
A月B日までは USB 経由で配布する事を許可します

本番配布用のプロビショニングプロファイルの場合

この証明書に添付された署名(公開鍵)がされている
XXXという ID のアプリは
A月B日まではストア経由で配布する事を許可します

仕組み (実行時)

端末側は、以下の手順でアプリが Apple に許可されていることを確認します。

  1. 署名を確認し、パッケージを開く
  2. パッケージの中からプロビショニングプロファイルを取り出す
  3. プロビショニングプロファイルに Apple の署名があることを確認しつつ、中身を開く
  4. 流通ルートやデバイス、アプリのIDが適切かどうかを確認する
  5. さらに、プロビショニングプロファイル内に添付された公開鍵を取り出し、パッケージングの署名と一致しているかを確認する
  6. ここまで確認できれば、Apple から許可されていると判断して実行する

※ 実際にどのように端末側が検証しているかが書かれた資料は、実は見つけられませんでした。憶測です。

補足

プロビショニングプロファイルも、開発者の証明書も、一般的な形式で提供されており、openssl で確認などができます。証明書の形式は、DER形式です。プロビショニングプロファイルは CMS 形式です。

まとめ

難しい…。