脆弱性対策方法

開発者の不注意や確認不足が、脆弱性につながることが理解できたと思います。
次は、サンプルコードを基に対策方法を学んでいきましょう。

脆弱性の原因

本シナリオでの脆弱性の原因は以下となります。
  • 「05データバックアップ」アプリのServiceを全てのアプリに公開している
    このアプリは、特定のアプリにのみServiceを公開することを想定しているので、Permissionで保護する事が対策となります。
    また、「05データバックアップクライアント」アプリには脆弱性はありませんが、「05データバックアップ」アプリのServiceをPermissionで保護するため、「05データバックアップクライアント」アプリにもPermissionの追加を行う必要があります。

対策方法の概要

実際に脆弱性のあるソースコードを確認し、修正してみましょう。
まず、「ソースコードを開く」ボタンをクリックし、「AndroidManifest.xml」を開いてください。

ソースコードを開く

修正前:
プロジェクト ComponentService
ソースファイル AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.go.ipa.sample.component.service"
    android:versionCode="1"
    android:versionName="1.0" >

   <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="8" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
<!-- ▼▼▼脆弱性のあるソースコード▼▼▼ -->
<!-- exported属性をtrueに設定。 -->
<service
    android:name=".BackupService"
    android:exported="true" >
</service>
<!-- ▲▲▲脆弱性のあるソースコード▲▲▲ -->

このアプリには脆弱性対策を行うべき箇所が3箇所あります。修正例は以下の通りです。
  • Permission使用の宣言を追加する
    修正前ソースコードの10行目と11行目の間にアプリで使用するPermissionの宣言を追加します。
    ServiceをPermissionで保護するためには、保護に使用するPermissionを使うことを宣言する必要があります。
    修正後ソースコードの11~13行にあたります。
    <uses-permission android:name="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE"/>
  • 独自のPermissionの定義を追加する
    上の修正に続けて、Serviceの保護に使用する独自のPermissionの定義を追加します。
    android:protectionLevelで設定するPermissionの保護レベルにsignatureを設定することにより、Permissionを定義した側のアプリと同じ署名を持ったアプリにのみPermissionの使用を許可します。
    修正後ソースコード16~18行目にあたります。
    <permission 
    	  android:name="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE" 
    	  android:protectionLevel="signature"/> 
  • ServiceをPermissionで保護する
    修正前ソースコードの31行目に、上で定義したServiceの保護に使用するPermissionの指定を追加します。
    これにより、このServiceには指定したPermissionを持つアプリしかアクセスできなくなります。
    修正前ソースコードの31行目末尾の「>」を削除し、31行目と32行目の間に以下のコード(赤文字部分)を追加してください。
    修正後ソースコード42行目にあたります。
    <service
        android:name=".BackupService"
        android:exported="true"
        android:permission="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE">
    </service>
    Permissionで保護するServiceのandroid:exported属性の設定も確認しておきましょう。
    android:exported属性が指定されていない、または、android:exported属性にfalseが設定されていた場合は、Serviceが非公開となり、指定したPermissionを持ったアプリからもアクセスできなくなってしまうためです。

修正後:
プロジェクト ComponentService
ソースファイル AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.go.ipa.sample.component.service"
    android:versionCode="1"
    android:versionName="1.0" >

	<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="8" />

    <!-- ▼▼▼脆弱性を修正したソースコード▼▼▼ --> 
    <uses-permission android:name="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE"/>
    <!-- ▲▲▲脆弱性を修正したソースコード▲▲▲ -->
    
    <!-- ▼▼▼脆弱性を修正したソースコード▼▼▼ --> 
    <permission 
    		android:name="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE"
            android:protectionLevel="signature"/>
    <!-- ▲▲▲脆弱性を修正したソースコード▲▲▲ -->
    
		<!-- ▼▼▼脆弱性を修正したソースコード▼▼▼ --> 
		<!-- exported属性をtrueに設定。 -->
		<service
		    android:name=".BackupService"
		    android:exported="true"
		    android:permission="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE">
		</service>
		<!-- ▲▲▲脆弱性を修正したソースコード▲▲▲ -->


最後に、Permissionで保護された「05データバックアップ」アプリのServiceを利用する「05データバックアップクライアント」アプリも同じPermissionを使用するよう修正しましょう。

「ソースコードを開く」ボタンをクリックし、「AndroidManifest.xml」を開いてください。

ソースコードを開く


修正前:
プロジェクト ComponentServiceClient
ソースファイル AndroidManifest.xml
<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="8" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

使用するPermissionが宣言されていません。このままだと、Serviceを起動しようとした際にSecurityExceptionが発生してしまいます。「05データバックアップ」アプリのServiceに設定したPermissionをアプリで使用するよう宣言しましょう。
修正前ソースコードの10行目と11行目の間に、Permissionの使用を宣言します。
修正後ソースコードの11行目にあたります。
<uses-permission android:name="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE"/>


修正後:
プロジェクト ComponentServiceClient
ソースファイル AndroidManifest.xml
   <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="8" />

    <uses-permission android:name="jp.go.ipa.sample.component.service.permission.LAUNCH_SERVICE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

対策のまとめ

「公開コンポーネントのアクセス制限不備」による脆弱性について、対策は以下のとおりです。
  • 対策
    公開ServiceをPermissionで保護する。
    android:permission属性を使用することで、同一のPermissionを持つアプリにのみアクセスを許可することが可能となります。
    設定したPermissionを持っていないアプリからコンポーネントにアクセスされた場合は、アクセスしようとした側でSecurityExceptionが発生し、処理が実行されることは無くなります。
  • 修正方法
    コンポーネントをPermissionで保護する際には以下について注意する事が必要です。
    • 自社製アプリにのみ公開する場合
      保護レベル「signature」を使ってコンポーネントのアクセス制限を行うと、より安全にコンポーネントを公開できます。 保護レベルが「signature」の場合、同じ署名(アプリの署名)を持つアプリにのみコンポーネントへのアクセスを許可することができます。
      作成者(作成社)が同じアプリ間でコンポーネントを公開する場合、「signature」Permissionを使用した保護が最も安心できる方法と言えます。

      保護レベルの詳細はAndroid Developersのサイトを参考にしてください。
      Android Developers-permissionの説明: http://developer.android.com/guide/topics/manifest/permission-element.html
    • 自社製でない特定のアプリにのみ公開する場合
      他社製のアプリに対してコンポーネント公開する場合は、「signature」レベルの保護を利用できません。 「signature」レベル以外のPermissionは、全てのアプリが使用できるため、保護レベル「signature」を使用できない場合、重要な機能や情報をもったコンポーネントを公開するのは避けた方が良いでしょう。
  • 参考情報
    • Permissionによる保護の限界
      Permissionを用いたコンポーネントの保護設定は、AndroidManifest.xmlに記載されているため、端末内のapkファイルが解析された場合、コンポーネントがどのようなPermissionで保護されているか調べることが可能です。 他社製のアプリに対して極めて重要な情報(口座番号のような金銭的被害に直結するような情報など)を扱うコンポーネントを公開しなければならない場合は、 アプリ内にPermissionによる保護を補完する独自のチェック処理を実装することが必要となります。 また、Permissionを偽装することにより、保護レベルを下げることも可能であることが分かっています。これも偽装を検知する独自のチェック処理を実装することが必要となります。
      これらについては、JSSECのガイドラインに記載があるのでそちらを参照してください。

      Androidアプリのセキュア設計・セキュアコーディングガイド【2013年4月1日版】
      http://www.jssec.org/report/securecoding.html