기기 관리 정책으로 보안 강화

기기 관리자 지원 중단. 일부 관리자 정책은 기기 관리자가 호출할 때 지원 중단된 것으로 표시되었습니다. 자세한 내용과 이전 옵션을 보려면 기기 관리자 지원 중단을 참고하세요.

Android 2.2 (API 수준 8)부터 Android 플랫폼은 Device Administration API를 통해 시스템 수준의 기기 관리 기능을 제공합니다.

이 강의에서는 기기 관리 정책을 시행하여 콘텐츠 액세스를 관리하는 보안 인식 애플리케이션을 만드는 방법을 알아봅니다. 특히 사용자에게 제한된 콘텐츠를 표시하기 전에 충분한 안전성의 화면 잠금 비밀번호가 설정되도록 애플리케이션을 구성할 수 있습니다.

정책 정의 및 선언

먼저 기능 수준에서 지원할 정책 종류를 정의해야 합니다. 정책은 화면 잠금 비밀번호 안전성, 만료 시간 제한, 암호화 등에 적용될 수 있습니다.

res/xml/device_admin.xml 파일에서 애플리케이션이 시행할 정책 세트를 선언해야 합니다. Android 매니페스트는 선언된 정책 세트도 참조해야 합니다.

선언된 각 정책은 DevicePolicyManager의 여러 관련 기기 정책 메서드에 상응합니다. 최소 비밀번호 길이와 최소 대문자 수의 정의가 두 가지 예입니다. 애플리케이션이 상응하는 정책이 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>

기기 관리 수신기 만들기

지원하겠다고 선언한 정책과 관련된 이벤트에 대한 알림을 받는 기기 관리 broadcast receiver를 만듭니다. 애플리케이션은 콜백 메서드를 선택적으로 재정의할 수 있습니다.

샘플 애플리케이션인 기기 관리자에서 사용자가 기기 관리자를 비활성화하면 구성된 정책이 공유 환경설정에서 삭제됩니다. 사용 사례와 관련된 비즈니스 로직 구현을 고려해야 합니다. 예를 들어 애플리케이션은 기기에서 민감한 정보를 삭제하고 원격 동기화를 사용 중지하고 관리자에게 알림을 보내는 등의 몇 가지 조합을 구현하여 보안 위험을 완화하기 위한 조치를 취할 수 있습니다.

broadcast receiver가 작동하려면 위 스니펫에 설명된 대로 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()에는 조건을 재평가하고 필요한 경우 사용자에게 기기 관리자 활성화 옵션을 표시하는 로직이 있어야 합니다.

기기 정책 컨트롤러 구현

기기 관리자가 성공적으로 활성화되면 애플리케이션은 요청된 정책으로 기기 정책 관리자를 구성합니다. 버전이 출시될 때마다 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를 통해 기존 비밀번호가 필요한 정책을 충족하는지 확인할 수 있습니다. 기존의 화면 잠금 비밀번호가 충분하지 않은 것으로 확인되면 기기 관리 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));
}