デバイス管理ポリシーによるセキュリティの強化

デバイス管理のサポート終了。一部の管理ポリシーは、デバイス管理者によって呼び出されたときに非推奨としてマークされています。移行オプションの詳細と移行オプションについては、 デバイス管理のサポート終了をご覧ください。

Android 2.2(API レベル 8)以降、Android プラットフォームでは、デバイス管理 API を通じてシステムレベルのデバイス管理機能を提供しています。

このレッスンでは、デバイス管理ポリシーを適用してコンテンツへのアクセスを管理するセキュリティ対応アプリを作成する方法を学びます。具体的には、制限付きコンテンツをユーザーに表示する前に、十分な強度の画面ロック パスワードが設定されているように設定できます。

ポリシーを定義して宣言する

まず、機能レベルでサポートするポリシーの種類を定義する必要があります。ポリシーにより、画面ロックのパスワードの安全度、有効期限のタイムアウト、暗号化などに対応できる場合があります。

アプリによって適用される、選択されたポリシーセットを res/xml/device_admin.xml ファイルで宣言する必要があります。Android マニフェストは、宣言されたポリシーセットも参照する必要があります。

宣言された各ポリシーは、DevicePolicyManager 内のいくつかの関連するデバイス ポリシー メソッドに対応しています(パスワードの最小長と大文字の最小最小数の 2 つの例です)。アプリが、対応するポリシーが XML で宣言されていないメソッドを呼び出そうとすると、実行時に SecurityException が発生します。アプリが他の種類のポリシーを管理する場合は、force-lock などの他の権限も使用できます。後で説明するように、デバイス管理者の有効化プロセスの一環として、宣言されたポリシーのリストがシステム画面に表示されます。

次のスニペットでは、res/xml/device_admin.xml でパスワード制限ポリシーを宣言しています。

<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-policies>
        <limit-password />
    </uses-policies>
</device-admin>

Android マニフェストで参照されるポリシー宣言 XML:

<receiver android:name=".Policy$PolicyAdmin"
    android:permission="android.permission.BIND_DEVICE_ADMIN">
    <meta-data android:name="android.app.device_admin"
        android:resource="@xml/device_admin" />
    <intent-filter>
        <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    </intent-filter>
</receiver>

デバイス管理レシーバーを作成する

サポートを宣言したポリシーに関連するイベントについて通知を受け取る、デバイス管理ブロードキャスト レシーバを作成します。アプリは、コールバック メソッドを選択的にオーバーライドできます。

サンプルアプリの Device Admin では、ユーザーがデバイス管理者を無効にすると、構成されたポリシーが共有設定から消去されます。ユースケースに関連するビジネス ロジックの実装を検討する必要があります。たとえば、アプリは、デバイス上の機密データの削除、リモート同期の無効化、管理者へのアラートなどを組み合わせて実装することで、セキュリティ リスクを軽減するためになんらかのアクションを実行できます。

ブロードキャスト レシーバが機能するためには、上記のスニペットに示すように、必ず Android マニフェストに登録してください。

Kotlin

class PolicyAdmin : DeviceAdminReceiver() {

    override fun onDisabled(context: Context, intent: Intent) {
        // Called when the app is about to be deactivated as a device administrator.
        // Deletes previously stored password policy.
        super.onDisabled(context, intent)
        context.getSharedPreferences(APP_PREF, Activity.MODE_PRIVATE).edit().apply {
            clear()
            apply()
        }
    }
}

Java

public static class PolicyAdmin extends DeviceAdminReceiver {

    @Override
    public void onDisabled(Context context, Intent intent) {
        // Called when the app is about to be deactivated as a device administrator.
        // Deletes previously stored password policy.
        super.onDisabled(context, intent);
        SharedPreferences prefs = context.getSharedPreferences(APP_PREF, Activity.MODE_PRIVATE);
        prefs.edit().clear().commit();
    }
}

デバイス管理を有効にする

ポリシーを適用する前に、ユーザーはデバイス管理者としてアプリを手動で有効にする必要があります。以下のスニペットは、ユーザーがアプリを有効にできる設定アクティビティをトリガーする方法を示しています。インテントに EXTRA_ADD_EXPLANATION エクストラを指定して、アプリがデバイス管理者になることをリクエストする理由をユーザーに強調する説明テキストを含めることをおすすめします。

図 1. デバイス ポリシーの説明を記述できるユーザー アクティベーション画面。

Kotlin

if (!policy.isAdminActive()) {

    val activateDeviceAdminIntent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)

    activateDeviceAdminIntent.putExtra(
            DevicePolicyManager.EXTRA_DEVICE_ADMIN,
            policy.getPolicyAdmin()
    )

    // It is good practice to include the optional explanation text to
    // explain to user why the application is requesting to be a device
    // administrator. The system will display this message on the activation
    // screen.
    activateDeviceAdminIntent.putExtra(
            DevicePolicyManager.EXTRA_ADD_EXPLANATION,
            resources.getString(R.string.device_admin_activation_message)
    )

    startActivityForResult(activateDeviceAdminIntent, REQ_ACTIVATE_DEVICE_ADMIN)
}

Java

if (!policy.isAdminActive()) {

    Intent activateDeviceAdminIntent =
        new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);

    activateDeviceAdminIntent.putExtra(
        DevicePolicyManager.EXTRA_DEVICE_ADMIN,
        policy.getPolicyAdmin());

    // It is good practice to include the optional explanation text to
    // explain to user why the application is requesting to be a device
    // administrator. The system will display this message on the activation
    // screen.
    activateDeviceAdminIntent.putExtra(
        DevicePolicyManager.EXTRA_ADD_EXPLANATION,
        getResources().getString(R.string.device_admin_activation_message));

    startActivityForResult(activateDeviceAdminIntent,
        REQ_ACTIVATE_DEVICE_ADMIN);
}

ユーザーが [有効にする] を選択すると、アプリがデバイス管理者になり、ポリシーの設定と適用を開始できます。

また、アプリは、ユーザーが [キャンセル] ボタン、戻るキー、またはホームキーを押して有効化プロセスを放棄するセットバック状況に対処できるように準備しておく必要もあります。したがって、ポリシー設定アクティビティの onResume() には、条件を再評価し、必要に応じてユーザーにデバイス管理の有効化オプションを提示するロジックが必要です。

Device Policy Controller を実装する

デバイス管理が正常に有効になると、アプリはリクエストされたポリシーを使用してデバイス ポリシー マネージャーを設定します。なお、Android にはリリースのたびに新しいポリシーが追加されています。新しいポリシーを使用し、なおかつ古いバージョンのプラットフォームをサポートする場合は、アプリケーションでバージョン チェックを実行することをおすすめします。たとえば、パスワードの下限(大文字)ポリシーは API レベル 11(Honeycomb)以降でのみ使用できます。次のコードは、実行時にバージョンを確認する方法を示しています。

Kotlin

private lateinit var dpm: DevicePolicyManager
private lateinit var policyAdmin: ComponentName

dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
policyAdmin = ComponentName(context, PolicyAdmin::class.java)

dpm.apply {
    setPasswordQuality(policyAdmin, PASSWORD_QUALITY_VALUES[passwordQuality])
    setPasswordMinimumLength(policyAdmin, passwordLength)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        setPasswordMinimumUpperCase(policyAdmin, passwordMinUpperCase)
    }
}

Java

DevicePolicyManager dpm = (DevicePolicyManager)
        context.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName policyAdmin = new ComponentName(context, PolicyAdmin.class);

dpm.setPasswordQuality(policyAdmin, PASSWORD_QUALITY_VALUES[passwordQuality]);
dpm.setPasswordMinimumLength(policyAdmin, passwordLength);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    dpm.setPasswordMinimumUpperCase(policyAdmin, passwordMinUpperCase);
}

この時点で、アプリケーションはポリシーを適用できます。アプリは実際に使用されている画面ロックのパスワードにアクセスできませんが、Device Policy Manager API を介して、既存のパスワードが必要なポリシーを満たしているかどうかを判断できます。既存の画面ロックのパスワードでは不十分であることが判明した場合、Device Management API は自動的に是正措置を講じません。設定アプリで、システム パスワード変更画面を明示的に起動するのは、アプリの役割です。次に例を示します。

Kotlin

if (!dpm.isActivePasswordSufficient) {
    // Triggers password change screen in Settings.
    Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD).also { intent ->
        startActivity(intent)
    }
}

Java

if (!dpm.isActivePasswordSufficient()) {
    ...
    // Triggers password change screen in Settings.
    Intent intent =
        new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
    startActivity(intent);
}

通常、ユーザーはなし、パターン、PIN(数字)、パスワード(英数字)など、使用可能なロックメカニズムのいずれかを選択できます。パスワード ポリシーが構成されると、ポリシーで定義されているものよりも脆弱なパスワード タイプが無効になります。たとえば、「数字」パスワードの品質が構成されている場合、ユーザーは PIN(数字)またはパスワード(英数字)のパスワードのみを選択できます。

適切な画面ロックのパスワードを設定してデバイスが適切に保護されると、アプリはセキュリティで保護されたコンテンツへのアクセスを許可します。

Kotlin

when {
    !dpm.isAdminActive(policyAdmin) -> {
        // Activates device administrator.
        ...
    }
    !dpm.isActivePasswordSufficient -> {
        // Launches password set-up screen in Settings.
        ...
    }
    else -> {
        // Grants access to secure content.
        ...
        startActivity(Intent(context, SecureActivity::class.java))
    }
}

Java

if (!dpm.isAdminActive(..)) {
    // Activates device administrator.
    ...
} else if (!dpm.isActivePasswordSufficient()) {
    // Launches password set-up screen in Settings.
    ...
} else {
    // Grants access to secure content.
    ...
    startActivity(new Intent(context, SecureActivity.class));
}