脆弱性対策方法

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

脆弱性の原因

本シナリオでの脆弱性の原因は以下となります。
  • 暗黙的Intentを使用して画像ファイルを受信するようにBroadcastReceiverを定義していることにより、画像ファイルが受信すべきでないアプリにも送られてしまう
    対策は2つ考えられます
    ここでは「Permissionを使用して想定外のBroadcastReceiverにIntentが受信されないようにする」対策を実施してみます。

対策方法の概要

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

ソースコードを開く

修正前:
プロジェクト ComponentBroadcast
ソースファイル 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.broadcast"
    android:versionCode="1"
    android:versionName="1.0">

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

    <application
        android:allowBackup="true"
<receiver
	android:name="jp.go.ipa.sample.component.broadcast.MessageReceiver">
	 <!-- ▼▼▼脆弱性のあるソースコード▼▼▼ -->
	<intent-filter>
	    <action android:name="sampleapp.message.receiver"/>
	</intent-filter>
	 <!-- ▲▲▲脆弱性のあるソースコード▲▲▲ -->
</receiver>

ソースコードを開く


修正前:
プロジェクト ComponentBroadcastSender
ソースファイル MainActivity.java
    /*
	 * 送信ボタンタップ
	 */
	public void onClickSend(View v) {
		// 画像の取得
		ListView listFriend = (ListView) findViewById(R.id.listFriend);
		int pos = listFriend.getCheckedItemPosition();

		// 画像が指定されていない場合は以降の処理は行わない
		if (pos <  0) {
			Toast toast = Toast.makeText(this, "画像を選択してください", Toast.LENGTH_SHORT);
			toast.setGravity(Gravity.AXIS_CLIP, 0, 0);
			toast.show();
			return;
		}
		String pictureName = (String) listFriend.getItemAtPosition(pos);

        // ▼▼▼脆弱性のあるソースコード▼▼▼
		// 暗黙的Intentを使用
		Intent intent = new Intent("sampleapp.message.receiver");

		intent.putExtra("pictureName", pictureName);
		sendBroadcast(intent);
		// ▲▲▲脆弱性のあるソースコード▲▲▲
	}

ComponentBroadcastには、脆弱性対策を行うべき箇所が1箇所あります。修正例は以下の通りです。
  • AndroidManifest.xml:10行目
    まず、送信側に求めるPermissionの使用を宣言します。
    修正前ソースコードの10行目と11行目の間に以下のコードを追加してください。
    <uses-permission android:name="jp.go.ipa.sample.component.broadcast.permission.receive"/>
    引き続き、Permissionを宣言します。
    <permission
        android:name="jp.go.ipa.sample.component.broadcast.permission.receive"
        android:protectionLevel="signature"/> 

    修正後ソースコードの12行目から〜16行目にあたります。
    なお、修正前ソースコードの30行目〜32行目は、BroadcastReceiverの定義を行っている部分ですが、今回の対策ではBroadcastReceiverの定義は修正しません。

ComponentBroadcastSenderには、脆弱性対策を行うべき箇所が1箇所あります。修正例は以下の通りです。
  • MainActivity.java:70行目
    発行するBroadcastにPermissionを設定するために、sendBroadcastの第2引数にPermissionの定義を追加します(赤文字部分)。
    これにより、同一のPermissionを持ったアプリにのみBroadcastの受信を許可します。
    sendBroadcast(intent,"jp.go.ipa.sample.component.broadcast.permission.receive");

修正後:
プロジェクト ComponentBroadcast
ソースファイル AndroidManifest.xml
	<!-- ▼▼▼脆弱性を修正したソースコード▼▼▼ -->
    <uses-permission android:name="jp.go.ipa.sample.component.broadcast.permission.receive" />

    <permission
        android:name="jp.go.ipa.sample.component.broadcast.permission.receive"
        android:protectionLevel="signature" />
	<!-- ▲▲▲脆弱性を修正したソースコード▲▲▲ -->

修正後:
プロジェクト ComponentBroadcastSender
ソースファイル MainActivity.java

    /*
	 * 送信ボタンタップ
	 */
	public void onClickSend(View v) {
		// 送信先の取得
		ListView listFriend = (ListView) findViewById(R.id.listFriend);
		int pos = listFriend.getCheckedItemPosition();

		// 送信先が指定されていない場合は以降の処理は行わない
		if (pos < 0) {
			Toast toast = Toast.makeText(this, "送信先を選択してください", Toast.LENGTH_SHORT);
			toast.setGravity(Gravity.AXIS_CLIP, 0, 0);
			toast.show();
			return;
		}
		String pictureName = (String) listFriend.getItemAtPosition(pos);

		// 暗黙的Intentを使用
		Intent intent = new Intent("sampleapp.message.receiver");
		
		intent.putExtra("pictureName", pictureName);
		
		// ▼▼▼脆弱性を修正したソースコード▼▼▼
		sendBroadcast(intent,"jp.go.ipa.sample.component.broadcast.permission.receive");
		// ▲▲▲脆弱性を修正したソースコード▲▲▲
		
	}

対策のまとめ

「暗黙的Intentの不適切な使用」による脆弱性について、対策は以下のとおりです。
  • 対策1
    暗黙的IntentをBroadcastする側でPermissionを指定する
    • 修正方法
      Broadcastを送信する際、sendBroadcastの第2引数にPermissionを指定する事で、指定したPermissionの利用を宣言しているアプリのBroadcastReceiverだけが画像データを受信できるようになります。
      Context#sendBroadcast(Intent intent, String receiverPermission)
      なお、BroadcastReceiverを公開した場合に、想定外のアプリからの画像データを受け取らないようにするためには、BroadcastReceiverをPermissionで保護します。これについては 公開コンポーネントのアクセス制限不備と同様の方法で実装することができます。
  • 対策2
    明示的Intentを使用するようにする
    • 修正方法
      BroadcastReceiverのintent-filterを削除して明示的Intentを受け取るように設計を変更します。
      intent-filterを削除し、BroadcastReceiverを公開(exported=true)にします。 Broadcastする側はBroadcastReceiverのIntentにクラス名を指定することにより想定外のアプリがIntentを受信する事がないようにします。 また、アプリ内で完結するBroadcastReceiverの場合はexported=false(非公開)に設定することで、他のアプリからBroadcastされたIntentを受け取る事がなくなります。