参考:Permissions | Android Developers
参考:Android Security
参考:Android アプリのセキュア設計・セキュアコーディングガイド
目次
パーミッション
Android では、通常特に宣言のない限りは、他のアプリや OS、ユーザに悪い影響を与える、いかなる操作もできないようにしています。
他のアプリのデータを読み取ったり、カメラや位置情報を利用したりするものがその例です。
これを特別に許可する仕組みとして、パーミッションが存在します。
パーミッションは、常に AndroidManifest で静的に宣言されるので、動的(実行時)にパーミッションを設定することはできません。
またパーミッションは、そのレベルによって、インストール時にユーザへ同意を求めるものや、同じパッケージ署名でなければならないもの、システムにしか権限を与えないものなどに分類されます。
通常、パーミッションは、外部に公開するコンポーネントに対して宣言を行い、その使用を制限します。
例えば、以下のような操作をしようとする場合に、パーミッションが要求されます。
- アプリケーションをシステムにインストールする際、特定の機能をアプリケーションが呼び出すことを防ぐため
- Activity を呼び出す際、他のアプリの Activity を起動するのを防ぐため
- ブロードキャストの送受信の際、ブロードキャストを受け取れる人や、送信できる人を制限するため
- ContentProvider へアクセスしたり操作したりする際
- サービスをバインドしたり開始したりする際
パーミッションの宣言
この項では、AndroidManifest における各種パーミッションの宣言について解説します。
<uses-permission>
他のアプリや、システムが宣言しているパーミッションを使用する宣言を行います。
パーミッションを宣言すると、インストール時にユーザに対して同意を求めるダイアログが表示されます。
パーミッションのレベルがdangerous
と宣言されているものを取得すると、同意画面上で優先的に表示されるようになります。<br /.
同じ署名でなければ利用できないパーミッションを、異なる署名のアプリから利用することはできません。
ここでパーミッションの取得宣言をしなかったにもかかわらず、パーミッションの必要な呼び出しを行った場合、SecurityException
が実行時にスローされます。
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.mixi.sample"
android:versionCode="1"
android:versionName="1.0">
<!-- ネットワークの状態を取得するためのパーミッションを取得する宣言 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 位置情報を取得するためのパーミッションを取得する宣言 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
</manifest>
<permission>
自分でパーミッションを宣言することもできます。
パーミッション名やアイコン、説明、レベルを設定します。
パーミッション名とアイコン、説明は、同意画面に表示されるので、分かりやすいものを設定します。
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.mixi.sample"
android:versionCode="1"
android:versionName="1.0">
<!-- パーミッションの定義 -->
<!-- android:name には、ユニークなパーミッション名を定義する -->
<permission
android:name="jp.mixi.sample.permission.READ_CONTENT_PROVIDER"
android:label="@string/permission_label_contentprovider"
android:icon="@drawable/ic_launcher"
android:description="@string/permission_description_contentprovider"
android:protectionLevel="signature">
</permission>
<application>
<!-- コンポーネントに対するパーミッション要求の設定 -->
<!-- android:permission 属性を利用して、このコンポーネントを呼び出す際にパーミッションを要求する -->
<!-- Activity の場合、Context#startActivity() や Context#startActivityForResult() の呼び出しでチェックされる -->
<activity
android:name="jp.mixi.sample.SamplePermissionActivity"
...
android:permission="jp.mixi.sample.permission.ACCESS_ACTIVITY">
</activity>
<!-- Service の場合、Context#startService() や Context#stopService()、Context#bindService() の呼び出しでチェックされる -->
<service
android:name="jp.mixi.sample.SamplePermissionService"
...
android:permission="jp.mixi.sample.permission.CALL_SERVICE">
</service>
<!-- BroadcastReceiver の場合、この BroadcastReceiver への Intent の送信可否を宣言することになる。 -->
<!-- もし許可のないまま BroadcastReceiver に Intent を送信しても、SecurityException とはならない。 -->
<!-- ただし、Intent はこの BroadcastReceiver に送信されない。 -->
<!-- SecurityException とはならないのは、Context#sendBroadcast() から戻った後にパーミッションがチェックされるからである。 -->
<!-- 逆に、Context#sendBroadcast() の時にパーミッションを宣言することもできる。 -->
<!-- この場合、宣言したパーミッションを取得している BroadcastReceiver のみがその Intent を受け取ることになる。 -->
<receiver
android:name="jp.mixi.sample.SamplePermissionReceiver"
...
android:permission="jp.mixi.sample.permission.CALL_BROADCAST_RECEIVER">
</receiver>
<!-- ContentProvider の場合、他のコンポーネントと異なり、READ と WRITE の 2 つの操作に対して、別々のパーミッションを設定できる -->
<!-- 両方のパーミッションを宣言した場合、WRITE のパーミッションを持っていても、READ も許可されるとは限らない点に注意する -->
<provider
android:name="jp.mixi.sample.SamplePermissionContentProvider"
...
android:readPermission="jp.mixi.sample.permission.READ_CONTENT_PROVIDER"
android:writePermission="jp.mixi.sample.permission.WRITE_CONTENT_PROVIDER">
</provider>
</application>
</manifest>
ProtectionLevel
Android のパーミッションで設定可能な保護レベルは下記のとおりです。複数設定することができます。
レベル | 意味 |
---|---|
normal | リスクの低いパーミッションで、システムや他のアプリケーション、ユーザへの影響が少ないものを意味します。システムは、インストール時に自動でこのパーミッションの許可を付与するので、ユーザに対する同意画面は表示されません(ただし、設定画面などからパーミッションの確認はできます)。 |
dangerous | リスクの高いパーミッションで、システムや他のアプリケーション、ユーザへの影響が大きいもの(プライベートなデータの参照など)を意味します。このため、インストール時には必ずユーザへの同意画面が表示されます。 |
signature | このパーミッションを宣言しているアプリケーションと同じ鍵で署名されたアプリケーションでなければ、このパーミッションに対する許可が付与されないことを意味します。署名が合えば、ユーザに同意画面を表示することなく、自動で許可を付与します。 |
signatureOrSystem | 同じ署名、または Android のシステムにのみ許可を付与します。通常、このオプションは使用しないことをおすすめします。 |
system | Android のシステムに許可を付与します。通常、このオプションは使用しないことをおすすめします。 |
development | 開発中のアプリケーションに許可を付与します。 |
アプリが依存する端末機能の使用宣言
カメラや位置情報など、端末のハードウェアないしソフトウェアの資源に依存する機能を有する場合、特別に、その宣言をしておく必要があります。
これは、その機能を有するかどうかが、デバイスごとに異なるため、予め依存する資源を宣言しておくことで、インストール可能かどうかを判断できるようにする為です。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.mixi.sample.di"
android:versionCode="1"
android:versionName="1.0">
<!-- カメラ機能の宣言。必ずしも必要としない場合は、android:required 属性を false とする。 -->
<uses-feature
android:name="android.hardware.camera"
android:required="false"/>
</manifest>
WebView
WebView は、指定された URL のページを読み込んだり、HTML を直接読み込んだりして、Web ページを表示するための View です。
WebView は、その特性から、いくつかの重要なセキュリティ対策項目があります。
参考:Androidセキュリティ勉強会 ~WebViewの脆弱性編~
JavaScript Interface
WebView には、JavaScript Interface という特別なインタフェースがあります。
これは、JavaScript からネイティブに宣言されたインタフェースを介することで、Java のコードを実行するものです。
公式リファレンスにも記述がありますが、信頼出来る Web ページ以外で、この JavaScript Interface を有効にしないことを強く推奨します。
なぜならば、JavaScript からJava のコードを呼び出すことが出来るため、不用意な設計をしていると、アプリのユーザ権限で様々な攻撃が可能となってしまうためです。
キャッシュ
WebView は、SQLiteDatabase を利用したキャッシュの仕組みを持っています。
この、SQLiteDatabase のキャッシュファイルは、/data/data/<app_package_name>/databases/webview.db
に保存されています。
キャッシュファイルには、ID やパスワードの情報も含まれますが、暗号化などは特にかけられていません。
他のアプリからのアクセスは拒否されますが、WebView 自身はすべてのパーミッションが付与されている状態であることから、WebView に何らかの攻撃手段を持たせてしまうと、ID やパスワードが抜き取られる危険性があります。
たとえば、標準ブラウザのキャッシュへは、標準ブラウザのアドレスバーに下記のように入力することでアクセスすることができます。
# 以下のどちらかの URL でアクセスします。
file:///data/data/com.android.browser/databases/webview.db
file:///data/data/com.google.android.browser/databases/webview.db