Activityのセキュリティについて

JSSECが公開している『Androidアプリのセキュア設計・セキュアコーディングガイド』の2016-09-01版を共有用にまとめているもののうち、「4.1. Activity を作る・利用する」のものとなります。

## チェックポイント
- [ ] アプリ内でのみ使用するActivityは非公開設定にしている
- [ ] 作成側で受信Intentの安全性を確認している
- [ ] 利用側で結果の受信データの安全性は確認している。

###  非公開Activity
* 作成側
- [ ] taskAffinityを指定していない
- [ ] launchModeを指定していない
- [ ] exported="false"を明示的に指定している
- [ ] Intent Filterを定義していない
* 利用側
- [ ] 送信するIntentにFLAG_ACTIVITY_NEW_TASKを設定していない
- [ ] 明示的Intentで呼びだしている
- [ ] センシティブな情報を送信する場合は、putExtra()を使用している(他の規約を守られている場合のみ安全)

### 公開Activity
* 作成側
- [ ] exported="true"を明示的に指定している
- [ ] 結果を返す場合、センシティブな情報を含めていない
* 利用側
- [ ] センシティブな情報を送信していない

### パートナ限定Activity
* 作成側
- [ ] taskAffinityを指定していない
- [ ] launchModeを指定していない
- [ ] exported="true"を明示的に指定している
- [ ] Intent Filterを定義していない
- [ ] 利用元アプリの証明書がホワイトリストに登録されていることを確認している
- [ ] パートナーアプリに開示してはいけない情報を返送していない
* 利用側
- [ ] 利用先Activityでアプリの証明書がホワイトリストに登録されていることを確認している
- [ ] 送信するIntent に、フラグFLAG_ACTIVITY_NEW_TASK を設定していない
- [ ] パートナーアプリに開示してはいけない情報を返送していない
- [ ] 開示して良い情報はputExtra()で送信している
- [ ] 明示的IntentによりActivityを呼びだしている
- [ ] startActivityForResult()でActivityを呼びだしている

### 自社限定Activity
* 作成側
- [ ] taskAffinity を指定していない
- [ ] launchMode を指定していない
- [ ] exported="true"を明示的に設定している
- [ ] Intent Filter を定義していない
- [ ] 独自定義Signature Permission を定義している
- [ ] 独自定義Signature Permission を要求宣言している
- [ ]  独自定義Signature Permission が自社アプリにより定義されていることを確認している
- [ ] 利用元アプリと同じ開発者鍵でAPK を署名している
* 利用側
- [ ]  独自定義Signature Permission を利用宣言している
- [ ]  独自定義Signature Permission が自社アプリにより定義されていることを確認している
- [ ]  利用先アプリの証明書が自社の証明書であることを確認している
- [ ]  センシティブな情報にはputExtra()を使用している
- [ ]  明示的Intent によりctivity を呼び出している
- [ ]  利用先アプリと同じ開発者鍵でAPK を署名している

## Tips
 1. Intentの安全確認
* どのようなActivityも、受信したIntentが安全とは考えてはいけません。非公開Activityも、公開Activityが他のアプリから受け取ったIntentのデータを転送される可能性があります
* 暗黙的Intentを利用すると、AndroidOS任せで、Activityを送信するため、マルウェアに送られる可能性があります
* 明示的Intentを利用した場合でも、他のアプリの公開activityを指定した場合、相手先Activityを含むアプリがマルウェアの可能性があります。また、宛先をパッケージ名で限定しても、同一のパッケージを持つ偽物アプリの可能性があります
* そのため、どのような状況でも、Intentの安全確認はすべきです
 2. タスクについて
* Android5.0未満では、自分自身のタスク以外の情報も読み取ることが出来ます。タスクのルートActivityに送信されたIntentはタスク履歴に追加され、ActivityManagerクラスを使うことでどのアプリからも自由に読みだすことが出来てしまいます。そのため、Activityが呼びだされた際に、タスクの新規生成、及び、既に存在するタスクのルートActivityを呼びだしてはいけません。
* 呼びだされたActivityがルートになるのを防ぐには
  1. taskAffinity を指定しない
  2. launchMode を指定しない
  3. Activity に送信するIntent にはFLAG_ACTIVITY_NEW_TASK を設定しない
  4.  呼びだされるActivityの起動モードにおいて、SingleTask,SinlgeInstanceで起動されたActivityはルートになる可能性があるため、これらのモードで起動しない
 3. 送信情報について
  * パートナー限定、公開Activityを使う場合、それぞれに公開して良い情報以外は送信してはいけません
  * Activityを利用する際に、ActivityMangerがIntentの内容のうち、利用先パッケージ名、利用先クラス名、intent#setDataで設定したURIをLogCatで出力するため、どのようなactivityであっても、これらにセンシティブな情報が含まれな異様にする必要があります
  * putExtraを使用した場合は、基本的には出力されませんが、状況によっては出力されます。また、明示的でも、暗黙的でも、先述の通り、マルウェアに読み取られる可能性があるので、センシティブな情報は出来る限り送らないのが好ましいです。
  * ルートActvitiy(タスクが生成された時に最初に呼びだされたActivity)にセンシティブな情報を送ってはいけません
  * Permissionにより保護されている機能を他のアプリに二次的に提供する場合は、提供先アプリに対して同一のPermissionを要求するなどして、その保護水準を維持しなければなりません
 4. 非公開Activityについて
* 非公開Activityは明示的Intentをつかえば、Intentを外部アプリに送ることがないため、もっとも安全です。ただし、ルートActivity等、上記のような状況では、読み取られる可能性があります。
* 非公開Activityに、Intent-filterを定義するのは禁止。意図せず、他のアプリのActivityを呼びだす可能性があります。発生状況としては、非公開Activityを暗黙的Intentで呼びだす場合、非公開ActivityにIntent Filterが存在し、かつ、別アプリの公開Activityのintent-filterの設定によっては、アプリケーションの選択ダイアログが出て、公開Activityに遷移出来てしまいます。
 5. その他
* 非公開Activity以外を呼びだす場合は、Intentが第三者に読み取られる可能性があります。
* 公開Activityはマルウェアが送信したIntentを受信する可能性があります。
* PreferenceActivityを継承したクラスが公開Activityとなっている場合、Fragment Injectionが発生する可能性があります。
Fragment Injectionについては、以下の記事がわかりやすいです。
http://qiita.com/shunXnegi/items/40da2e1a32ecfd09b94f


## 参考

『Android アプリのセキュア設計・セキュアコーディングガイド』【2016年9月1日版】
https://www.jssec.org/dl/android_securecoding.pdf