脆弱性対策方法

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

脆弱性の原因

本シナリオでの脆弱性の原因は以下となります。
  • 画像アップロードのActivityを全てのアプリに公開している。
    このアプリは、他のアプリとの連携を考えているものではないので、対象Activityが全てのアプリに公開されていることが脆弱性の原因となっています。

対策方法の概要

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

ソースコードを開く

修正前:
プロジェクト ComponentActivityExported
ソースファイル AndroidManifest.xml
        <!-- ▼▼▼脆弱性のあるソースコード▼▼▼ -->
        <!-- exported属性をtrueに設定。 -->
        <activity
            android:name="jp.go.ipa.component.activity.exported.UploadActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:exported="true"/>
        <!-- ▲▲▲脆弱性のあるソースコード▲▲▲ -->

このアプリには脆弱性対策を行うべき箇所が1箇所あります。修正例は以下の通りです。
  • 37行目
    android:exported属性に設定している値をtrueからfalseに修正します。
    android:exported属性は、コンポーネントを他のアプリに対して公開するかどうかを指定する項目です。
    これをfalseに設定することで、Activityは非公開となり、他アプリから呼び出すことができなくなります。
    37行目を以下のようにfalse(赤文字部分)に修正します。
    android:exported="false"
    このアプリでは使用していませんが、exportedが未定義でintent-filterが存在していた場合はexportedにtrueを設定していた場合と同様にコンポーネントは公開されます。
    非公開にしたい場合はIntentFilterを削除するか、exportedにfalseを設定する記述を追加しましょう。

修正後:
プロジェクト ComponentActivityExported
ソースファイル AndroidManifest.xml
        <!-- ▼▼▼脆弱性のあるソースコード▼▼▼ -->
        <!-- exported属性をfalseに設定。 -->
        <activity
            android:name="jp.go.ipa.component.activity.exported.UploadActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:exported="false"/>
        <!-- ▲▲▲脆弱性のあるソースコード▲▲▲ -->

対策のまとめ

「非公開コンポーネントのアクセス制限不備」による脆弱性について、対策は以下のとおりです。
  • 対策
    exported属性をfalseにする
  • 修正方法
    Activityを非公開にする際には以下について注意する事が必要です。
    • IntentFilterを設定した場合
      android:exported属性にfalseを設定した場合であってもIntentFilterを設定した場合は他のアプリからActivityを呼び出し可能となります。(android:exported属性にtrueを設定した場合と同様の動作)
  • 参考情報
    コンポーネントを他のアプリに公開したい場合、android:exported属性にtrueを設定しますが、これは非常に危険な状態です。他のアプリからのアクセスを制限し、コンポーネントを保護する必要があります。
    他のアプリからコンポーネントを保護する方法として、ここではPermissionを用いて他アプリからのアクセスを制限する一例を挙げます。

    Android OSの様々な機能をアプリが利用するためには、「AndroidManifest.xml」内にPermissionを宣言する必要があります。
    (Permissionについては、「不必要な権限の取得」を参照)

    コンポーネントのアクセス制限にPermissionを使用する場合、「AndroidManifest.xml」に使用するPermissionを記述します。
    使用するPermissionはAndroid OSが用意しているものに加え、独自のPermissionを作成して使用することもできます。
    Android OSの機能を使用する場合と同様に、Permissionを持たないアプリがコンポーネントにアクセスした場合、SecurityExceptionが発生し、コンポーネントの機能を利用することができません。
    これにより、同じPermissionを持つアプリにのみ、コンポーネントへのアクセスを許可することが可能になります。

    Permissionを用いたコンポーネントの保護例は以下の通りです。
    <!--独自Permissionの宣言-->
    <permission android:name="jp.go.ipa.permission.READ_DATA">
    <!--独自Permissionの利用-->
    <uses-permission android:name="jp.go.ipa.permission.READ_DATA"/>
    <activity android:name="ProtectedActivity"
    	android:label="@string/app_name"
    	android:permission="jp.go.ipa.permission.READ_DATA"/>
    													

    保護レベル「signature」を使ってコンポーネントのアクセス制限を行うと、より安全にコンポーネントを公開できます。 保護レベルが「signature」の場合、同じ署名(アプリの署名)を持つアプリにのみコンポーネントへのアクセスを許可することができます。
    作成者(作成社)が同じアプリ間でコンポーネントを公開する場合、「signature」Permissionを使用した保護が最も安心できる方法と言えます。

    <!--独自Permissionの宣言-->
    <permission android:name="jp.go.ipa.permission.READ_DATA"
    	android:protectionLevel="signature"/>
    <!--独自Permissionの利用-->
    <uses-permission android:name="jp.go.ipa.permission.READ_DATA"/>
    <activity android:name="ProtectedActivity"
    	android:label="@string/app_name"
    	android:permission="jp.go.ipa.permission.READ_DATA"/>
    													

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