知っていると幸せ？Androidセキュアコーディング【Activity編】


#はじめに
納期に追われ、完成を優先してコーディングをしていると、
どうしても二の次にしてしまう（自分だけ？）のがセキュリティ対策。

今回、日本スマートフォンセキュリティ協会のコーディングガイド（※）を読む機会があり、
備忘録を兼ねて、知っておくと幸せになれるセキュアコーディングをメモします。

今回はActivity編です♪

###この記事の位置付け
ここではチェックポイントのみ記載するので、実際のソースや詳細な説明は資料を参照してください。
※『Androidアプリのセキュア設計・セキュアコーディングガイド』
　【2018年9月1日版】
https://www.jssec.org/report/securecoding.html


##1. "exported"設定を必ず記載する
公開、非公開に関わらず明示するのがマナー。（ちなみにdefaultは"expored = true"）
外部アプリに公開する場合を除き、”false”を設定します。

なお、「exported = false」とした場合はIntent-filterは設定しない方が吉です。
例えば、アプリAのActivityをアプリAから暗黙的に起動した場合、アプリBで同じfilterを定義をしていた場合は、アプリAとアプリBの両方がIntentを受信することになります。

もしIntentに顧客情報を詰めていて、アプリBがマルウェアだったら・・怖いですねー（笑）



##2. "taskAffinity"を指定しない
この設定は例外なく未指定としましょう。（未指定のため記載不要）

アプリ内のActivityは、デフォルトだと全て同じタスクに属しますが、
この設定でそのActivityだけ別タスクに割り当てることができます。
タスクを変更するとIntentをマルウェアで読み取られる可能性があるため危険です。

##3. "launchMode"を指定しない
2.で別タスクで起動する危険性を書きましたが、
lauchModeも別タスクでActivityを起動する原因になるため、基本は"standard"(デフォルト)とします。
（セキュアコーディングガイドでは"standard"一点推しですが、"singleTop"も恐らく大丈夫です）

またセキュリティの観点以外でも、"singleTask"と"singleInstance"は画面遷移の挙動が不自然となるため、UXの観点からGoogleさんも使用を推奨していません。

| Launch Mode          | 新タスクの生成  |
|:---------------------|:------------:|
| standard (default)   | されない       |
| singleTop            | されない       |
| singleTask （※1）      | される         |
| singleInstance （※2）  | される         |
※1 Activityが既にある場合、他のActivityはfinish()される
※2 singleTaskと同じだが、Activityが属するタスクはそのActivityのインスタンスのみ唯一保持する。


##4. "FLAG_ACTIVITY_NEW_TASK"を指定しない
Activityを起動する時に指定するパラメータですが、
この指定を受けたActivityは別タスクで起動されます。

せっかく起動先のActivityを"launchMode = standard"としても別タスクで起動されてしまうため、
仕様を満たすためにやむを得ず使う以外は封印した方が良いです。

余談ですが、startActivityForResult()の結果なども受け取れなくなってしまうため、
起動後の動きも追うことができなくなります。

##5. 受信Intentをチェックする
受信したIntentにはどんなデータが含まれているか分からないため、チェックをしておいた方が幸せです。
公開Activityはもちろん、非公開Activityでもユーザが入力したデータをIntentに詰めることもあるので、以下の2点をチェックしましょう。

 - 受け取ったデータが想定した形式、かつ範囲内に収まる値か？
 - そのデータを受け取った後、想定外の動作をしないことを保証できるか？

##6. Signature Permissionを使う
自社限定Activityにおいて有効な手段です。
自社内であればアプリ同士の署名を同じにできるため、署名チェックを行うことでより強固にできます。
独自Permissionを定義し、パーミッションレベルを"signature"で定義すればOKです。

##7. 結果情報の返送に注意
起動元のアプリが悪意のあるアプリの場合、センシティブな情報を返却すると悪用されてしまいます。
公開Activityやパートナー限定Activityの場合は、結果情報の漏洩に注意しましょう。

##8. 明示的Intentを使う
1.でも説明しましたが、暗黙的IntentはIntent-filterの設定をすれば複数のアプリで受信可能です。
必要な場合を除き、明示的に起動しましょう。

##9. 利用元アプリの証明書を確認する
利用者が特定できているパートナー限定Activityにおいて有効な手段です。
事前に許可をしたアプリの証明書のハッシュ値をホワイトリストに保存しておくことで、
登録済みのハッシュ値を持つアプリのみ連携を許可できます。

##10. 情報のセットはputExtra()を使う
Logcat未使用の場合も、ActivityManagerはActivityに関する以下のログを出力します。
・パッケージ名
・利用先クラス名
・Intent.setData()で設定したURI

不要な情報の出力を防ぐため、情報のセットはputExtra()を使いましょう。
例えば以下のような処理を書いた場合、Logcatにアドレスが表示されます。

```txt:Logcatに出力される例
Uri uri = Uri.parse("mailto:test@gmail.com");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(intent);
```

```txt:Logcatに出力されない例
Uri uri = Uri.parse("mailto:");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri); 
intent.putExtra(Intent.EXTRA_EMAIL, new String[] {"test@gmail.com"}); 
startActivity(intent);
```

##11. 情報の2次使用に注意
Permissionにより保護している情報を他アプリへ二次的に提供する場合は、
提供先のアプリにも同レベルの保護水準で情報を扱ってもらう必要があります。

例えば、「android.permission.READ_CONTACTS」を利用宣言していて、
連絡先データにアクセス可能なアプリがあった場合、
その連絡先データをPermission宣言のないアプリへ渡すことは不適切です。

そのようなケースでは、データをもらう側のアプリも同じPermissionを
利用宣言しているか確認してから渡しましょう。

#まとめ
一つ一つは当たり前のようで、意外な見落としポイントがあったりしますね。
脅威に負けない堅牢なアプリを作りましょう！
BroadCast編、Service編なども作っていきたいです。