보안

이 가이드의 기능은 기기 정책 컨트롤러 (DPC) 앱에서 구현할 수 있는 보안 관리 기능을 설명합니다. 이 문서에는 코드 샘플이 포함되어 있으며 Test DPC 앱을 Android 엔터프라이즈 기능의 샘플 코드 소스로 사용할 수도 있습니다.

DPC 앱은 개인 기기의 프로필 소유자 모드로 실행되거나, 완전 관리형 기기의 기기 소유자 모드에서 실행될 수 있습니다. 다음 표는 DPC가 프로필 소유자 모드 또는 기기 소유자 모드에서 실행될 때 사용할 수 있는 기능을 나타냅니다.

기능 프로필 소유자 기기 소유자
앱 액세스 사용 중지
알 수 없는 소스의 앱 차단하기
Google Play에서 계정 제한하기
엔터프라이즈 초기화 보호 사용 설정하기
엔터프라이즈 프로세스 로그 및 원격 버그 신고 모니터링
클라이언트 인증서에 대한 액세스 권한 부여 및 삭제
보안 비밀번호 재설정
직장 프로필 보안 인증 질문

앱 액세스 차단

하루 중 특정 시간 또는 특정 요일에 직원이 Android 지원 기기에서 게임을 플레이하거나 YouTube를 시청하지 못하도록 차단하려는 조직의 경우 DPC를 사용하면 앱에 대한 액세스를 일시적으로 사용 중지할 수 있습니다.

앱 액세스를 사용 중지하기 위해 기기 소유자 또는 프로필 소유자 모드에서 실행되는 DPC가 setPackagesSuspended()를 구성한 다음, 선택한 앱이 사용 중지된 것처럼 작동합니다 (Google 런처에서 앱이 비활성화됨). 사용자가 앱을 탭하면 앱이 정지되었다는 시스템 대화상자가 표시됩니다.

앱이 정지된 동안에는 활동을 시작할 수 없으며 패키지에 대한 알림이 표시되지 않습니다. 정지된 패키지는 개요 화면에 표시되지 않고, 대화상자 (토스트 메시지 및 스낵바 포함)를 표시할 수 없으며, 오디오를 재생하거나 기기를 진동시킬 수도 없습니다.

런처는 isPackageSuspended() 메서드를 호출하여 앱이 정지되었는지 확인할 수 있습니다. 앱 정지를 구성하는 방법에 관한 자세한 내용은 setPackagesSuspended를 참고하세요.

알 수 없는 소스의 앱 차단

Google Play (또는 다른 신뢰할 수 있는 앱 스토어)에서 설치되지 않은 앱을 알 수 없는 소스의 앱이라고 합니다. 사용자가 이러한 앱을 설치하면 기기와 데이터의 위험이 높아질 수 있습니다.

타인이 알 수 없는 소스의 앱을 설치하지 못하게 하기 위해 완전 관리형 기기 및 직장 프로필의 관리자 구성요소에 DISALLOW_INSTALL_UNKNOWN_SOURCES 사용자 제한을 추가할 수 있습니다.

직장 프로필 기기 전체 제한

직장 프로필 관리자가 DISALLOW_INSTALL_UNKNOWN_SOURCES를 추가하면 직장 프로필에만 제한사항이 적용됩니다. 그러나 직장 프로필 관리자는 Google Play의 관리 구성을 설정하여 기기 전체 제한을 설정할 수 있습니다. 기기 전체 제한은 설치된 Google Play 앱 버전이 80812500 이상이면 Android 8.0 이상에서 사용할 수 있습니다.

앱 설치를 Google Play로 제한하려면 다음 단계를 따르세요.

  1. Google Play 패키지 com.android.vending의 관리 구성 번들을 설정합니다.
  2. 번들에서 verify_apps:device_wide_unknown_source_block 키의 불리언 값을 입력합니다.
  3. ENSURE_VERIFY_APPS 사용자 제한을 추가합니다.

다음 예는 Google Play에서 이 설정을 지원하는지 확인하고 값을 true로 설정하는 방법을 보여줍니다.

Kotlin

internal val DEVICE_WIDE_UNKNOWN_SOURCES = "verify_apps:device_wide_unknown_source_block"
internal val GOOGLE_PLAY_APK = "com.android.vending"

// ...

// Add the setting to Google Play's existing managed config. Supported in
// Google Play version 80812500 or higher--older versions ignore unsupported
// settings.
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
var existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putBoolean(DEVICE_WIDE_UNKNOWN_SOURCES, true)
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig)

// Make sure that Google Play Protect verifies apps.
dpm.addUserRestriction(adminName, UserManager.ENSURE_VERIFY_APPS)
dpm.addUserRestriction(adminName, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)

Java

static final String DEVICE_WIDE_UNKNOWN_SOURCES =
    "verify_apps:device_wide_unknown_source_block";
static final String GOOGLE_PLAY_APK = "com.android.vending";

// ...


// Add the setting to Google Play's existing managed config. Supported in
// Google Play version 80812500 or higher--older versions ignore unsupported
// settings.
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
Bundle existingConfig =
    dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putBoolean(DEVICE_WIDE_UNKNOWN_SOURCES, true);
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig);

// Make sure that Google Play Protect verifies apps.
dpm.addUserRestriction(adminName, UserManager.ENSURE_VERIFY_APPS);
dpm.addUserRestriction(adminName, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);

시스템 설정의 사용자 인터페이스는 활성 상태로 유지되지만 시스템에서 앱 설치를 차단합니다. 이 제한사항은 향후 설치에 영향을 미치며 이전에 설치된 앱은 기기에 유지됩니다. 기기 사용자는 Android 디버그 브리지 (adb)를 사용하여 개인 프로필에 앱을 계속 설치할 수 있습니다.

알 수 없는 소스에 관한 자세한 내용은 대체 배포 옵션을 참고하세요.

Google Play에서 계정 제한

조직에서 개인 Google 계정을 추가 (예: Gmail에서 메일 읽기)하도록 허용하지만 개인 계정으로는 앱을 설치하는 것은 원하지 않을 수 있습니다. DPC는 사용자가 Google Play에서 사용할 수 있는 계정 목록을 설정할 수 있습니다.

완전 관리형 기기 또는 직장 프로필의 관리자 구성요소는 Google Play의 관리 구성을 설정하여 계정을 제한할 수 있습니다. 계정 제한사항은 설치된 Google Play 앱의 버전이 80970100 이상인 경우에 사용할 수 있습니다.

Google Play에서 계정을 제한하려면 다음 단계를 따르세요.

  1. Google Play 패키지 com.android.vending의 관리 구성 번들을 설정합니다.
  2. 번들에서 쉼표로 구분된 이메일 주소를 allowed_accounts 키의 문자열 값으로 입력합니다.

다음 예에서는 계정을 제한하는 방법을 보여줍니다.

Kotlin

internal val ALLOWED_ACCOUNTS = "allowed_accounts"
internal val GOOGLE_PLAY_APK = "com.android.vending"

// ...

// Limit Google Play to one work and one personal account. Use
// a comma-separated list of account email addresses (usernames).
val googleAccounts = "ali@gmail.com,ali.connors@example.com"

// Supported in Google Play version 80970100 or higher.
val existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putString(ALLOWED_ACCOUNTS, googleAccounts)
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig)

Java

static final String ALLOWED_ACCOUNTS = "allowed_accounts";
static final String GOOGLE_PLAY_APK = "com.android.vending";

// ...


// Limit Google Play to one work and one personal account. Use
// a comma-separated list of account email addresses (usernames).
String googleAccounts = "ali@gmail.com,ali.connors@example.com";

// Supported in Google Play version 80970100 or higher.
Bundle existingConfig =
    dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putString(ALLOWED_ACCOUNTS, googleAccounts);
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig);

Google Play를 직장 계정으로만 제한하려면 DPC가 계정의 이메일 주소를 알게 되는 즉시 allowed_accounts를 단일 관리 계정으로 설정합니다. 빈 문자열은 Google Play에서 계정을 사용하지 못하게 합니다.

엔터프라이즈 초기화 보호 사용 설정

엔터프라이즈 초기화 보호 기능을 사용하면 조직에서 초기화된 기기를 프로비저닝할 수 있는 Google 계정을 지정할 수 있습니다.

소비자 초기화 보호는 기기 도난을 방지하도록 설계되었습니다. 설정 마법사에서 승인되지 않은 초기화 (예: EMM 사용) 후 누구나 기기를 프로비저닝할 수 있도록 허용하기 전에, 사용자에게 이전에 기기의 개인 프로필에 있던 Google 계정에 대해 인증하도록 요구합니다.

엔터프라이즈 환경에서 초기화는 직원이 퇴사할 때 직원 기기를 관리하는 데 중요한 도구입니다. 하지만 조직에서 직원의 계정 사용자 인증 정보를 모르면 초기화 보호로 인해 조직이 다른 직원에게 기기를 발급하지 못할 수 있습니다.

초기화 후 프로비저닝 제어

기기 소유자 모드에서 실행하는 경우 DPC는 setFactoryResetProtectionPolicy()를 사용하여 초기화 후 기기를 프로비저닝하도록 승인된 계정을 제어할 수 있습니다. 이 구성을 null로 설정하거나 빈 목록으로 설정하면 초기화 후 기기를 프로비저닝하도록 승인된 계정이 기기의 개인 프로필에 있는 계정입니다.

DPC는 완전 관리형 기기의 전체 기간 동안 이러한 계정을 구성할 수 있습니다.

  1. IT 관리자는 특수 값 me를 사용하여 People API의 people.get 메서드를 사용할 수 있습니다. 이렇게 하면 로그인한 계정의 userId가 검색됩니다. userIDresourceName 키에 정수 문자열로 people/[userId] 형식으로 반환됩니다. 새로 만든 계정은 72시간 동안 초기화 목적으로 사용하지 못할 수 있습니다.
  2. 초기화 후 한 명 이상의 IT 관리자가 기기를 잠금 해제하도록 할 수도 있습니다. 각 IT 관리자에게 Google 계정에 로그인하고 1단계를 따라 userId를 공유하도록 합니다. 그러면 다음 단계에서 이 userIds를 목록에 추가할 수 있습니다.
  3. DPC는 setFactoryResetProtectionPolicy()를 사용하여 적절한 앱 제한을 설정하여 초기화 기기를 프로비저닝할 수 있는 userId 목록을 설정합니다.
  4. DPC는 브로드캐스트 com.google.android.gms.auth.FRP_CONFIG_CHANGED를 명시적 인텐트로 전송하여 백그라운드 제한으로 인해 삭제되는 것을 방지함으로써 초기화 후 기기를 프로비저닝할 수 있는 계정을 사용 설정합니다.

Kotlin

const val ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

// List of userId that can provision a factory reset device.
// You can use the value returned calling people/me endpoint.
val accountIds = listOf("000000000000000000000")

dpm.setFactoryResetProtectionPolicy(
    adminName,
    FactoryResetProtectionPolicy.Builder()
        .setFactoryResetProtectionAccounts(accountIds)
        .setFactoryResetProtectionEnabled(true)
        .build()
)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

// List of userId that can provision a factory reset device.
// You can use the value returned calling people/me endpoint.
List<String> accountIds = new ArrayList<String>();
accountIds.add("000000000000000000000");

dpm.setFactoryResetProtectionPolicy(
    adminName,
    new FactoryResetProtectionPolicy.Builder()
        .setFactoryResetProtectionAccounts(accountIds)
        .setFactoryResetProtectionEnabled(true)
        .build());

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

레거시

API 수준 30에서 도입된 setFactoryResetProtectionPolicy()를 사용할 수 없는 기기의 경우 DPC는 setApplicationRestrictions를 사용하여 선택된 계정을 com.google.android.gms 패키지의 factoryResetProtectionAdmin 관리 구성에 추가할 수 있습니다.

Kotlin

const val GOOGLE_PLAY_APK = "com.android.vending"
const val FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin"
const val DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

val existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, false)
newConfig.putString(FACTORY_RESET_PROTECTION_ADMIN, googleAccounts)
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String GOOGLE_PLAY_APK = "com.android.vending";
static final String FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin";
static final String DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

Bundle existingConfig =
        dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, false);
newConfig.putStringArray(FACTORY_RESET_PROTECTION_ADMIN,
        accountIds.toArray(new String[accountIds.size()]));
dpm.setApplicationRestrictions(adminName, GOOGLE_PLAY_APK, newConfig);

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

엔터프라이즈 초기화 보호 사용 중지

초기화 보호 기능을 사용 중지하려면 DPC에서 setFactoryResetProtectionPolicy()를 사용하여 null 값을 전달하면 됩니다.

Kotlin

const val ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

dpm.setFactoryResetProtectionPolicy(adminName, null)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String ACTION_FRP_CONFIG_CHANGED =
    "com.google.android.gms.auth.FRP_CONFIG_CHANGED";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

dpm.setFactoryResetProtectionPolicy(adminName, null);

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

레거시

API 수준 30에서 도입된 setFactoryResetProtectionPolicy()를 사용할 수 없는 기기의 경우 DPC는 setApplicationRestrictions를 사용하여 com.google.android.gms 패키지의 disableFactoryResetProtectionAdmin 관리 구성에서 true의 키 값을 설정할 수 있습니다.

Kotlin

const val GOOGLE_PLAY_APK = "com.android.vending"
const val FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin"
const val DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin"
const val GMSCORE_PACKAGE = "com.google.android.gms"

// ...

val existingConfig = dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK)
val newConfig = Bundle(existingConfig)
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, true)

dpm.setApplicationRestrictions(
    adminName, GOOGLE_PLAY_SERVICES_PACKAGE, restrictions
)

val frpChangedIntent = Intent(ACTION_FRP_CONFIG_CHANGED)

frpChangedIntent.setPackage(GMSCORE_PACKAGE)
context.sendBroadcast(frpChangedIntent)

Java

static final String GOOGLE_PLAY_APK = "com.android.vending";
static final String FACTORY_RESET_PROTECTION_ADMIN = "factoryResetProtectionAdmin";
static final String DISABLE_FACTORY_RESET_PROTECTION_ADMIN = "disableFactoryResetProtectionAdmin";
static final String GMSCORE_PACKAGE = "com.google.android.gms";

// ...

Bundle existingConfig =
        dpm.getApplicationRestrictions(adminName, GOOGLE_PLAY_APK);
Bundle newConfig = new Bundle(existingConfig);
newConfig.putBoolean(DISABLE_FACTORY_RESET_PROTECTION_ADMIN, true);

dpm.setApplicationRestrictions(
    adminName, GOOGLE_PLAY_SERVICES_PACKAGE, restrictions);

Intent frpChangedIntent = new Intent(ACTION_FRP_CONFIG_CHANGED);

frpChangedIntent.setPackage(GMSCORE_PACKAGE);
context.sendBroadcast(frpChangedIntent);

엔터프라이즈 프로세스 로그 및 원격 버그 보고서 모니터링

EMM 콘솔에서 관리자는 엔터프라이즈 프로세스 로그 및 원격 버그 신고를 사용하여 완전 관리형 기기를 모니터링할 수 있습니다.

엔터프라이즈 기기 활동 로깅

기기 소유자 모드에서 실행되는 DPC는 앱 실행, Android 디버그 브리지 (adb) 활동 및 화면 잠금 해제를 비롯한 기기 활동을 원격으로 추적하여 의심스러운 활동을 식별할 수 있습니다. 로그 처리에는 사용자 동의가 필요하지 않습니다.

로깅을 사용 설정 또는 사용 중지하기 위해 DPC는 setSecurityLoggingEnabled()를 호출합니다.

새 로그 배치를 사용할 수 있으면 DeviceAdminReceiveronSecurityLogsAvailable() 콜백을 수신합니다. 콜백을 수신한 후 로그를 검색하기 위해 DPC는 retrieveSecurityLogs()를 호출합니다.

DPC는 retrievePreRebootSecurityLogs()를 호출하여 이전 재부팅 주기에서 생성된 보안 로그를 가져올 수도 있습니다. 마지막 기기 재부팅과 이전 재부팅 사이의 간격입니다. retrieveSecurityLogs()를 지원하지 않는 기기는 null를 반환합니다. 앱이 retrievePreRebootSecurityLogs()retrieveSecurityLogs()를 모두 사용하여 로그를 검색하는 경우 중복 항목을 확인해야 합니다.
참고: 이 기능은 사용자가 한 명이거나 연결된 사용자가 있는 완전 관리형 기기의 활동만 로깅합니다. 이 기능은 기기 전체 활동을 기록하므로 개인 기기에서는 작동하지 않습니다.

이 설정은 다음과 같은 유형의 작업을 로깅하므로 보안 이벤트 후 감사에 유용할 수 있습니다.

  • 앱이 새로 시작될 때마다 이렇게 하면 손상된 앱으로 시작하는 멀웨어가 있는지 확인할 수 있습니다.
  • 기기에서 잠금 해제 시도가 실패했습니다. 이를 통해 단기간에 잠금 해제 시도가 여러 번 실패했는지 식별할 수 있습니다.
  • 사용자가 USB 케이블을 사용하여 기기를 컴퓨터에 연결할 때 잠재적으로 위험한 adb 명령어

로그를 읽는 방법에 관한 자세한 내용은 SecurityLog를 참고하세요.

개발하고 테스트하는 동안 DPC에 기존 보안 로그가 사용 가능하도록 시스템에서 강제할 수 있습니다. 전체 배치를 기다릴 필요가 없습니다. Android 9.0 (API 수준 28) 이상에서는 터미널에서 다음 Android 디버그 브리지 (adb) 명령어를 실행합니다.

adb shell dpm force-security-logs

시스템은 도구 사용 빈도를 제한하고 터미널 출력의 의도적인 속도 저하를 보고합니다. 사용 가능한 로그가 있는 경우 DPC는 onSecurityLogsAvailable() 콜백을 수신합니다.

원격으로 버그 신고 요청

기기 소유자 모드로 실행되는 DPC는 사용자가 한 명 또는 연결된 사용자만 있는 사용자 기기의 버그 신고를 원격으로 요청할 수 있습니다. 버그 신고는 버그 신고가 요청된 바로 그 순간의 기기 활동을 캡처하지만, logcat 버퍼가 새로고침되는 빈도에 따라 이전 몇 시간 동안의 활동도 포함할 수 있습니다.

원격으로 버그 신고를 요청하기 위해 DPC는 requestBugreport()를 호출합니다.

클라이언트 인증서에 대한 액세스 권한 부여 및 삭제

프로필 소유자 또는 기기 소유자 모드에서 실행되는 DPC가 서드 파티 앱에 인증서 관리 기능을 부여하면 앱은 사용자의 개입 없이 설치하는 인증서에 대한 액세스 권한을 자체적으로 부여할 수 있습니다. 프로필의 모든 앱이 액세스할 수 있는 인증서를 설치하려면 installKeyPair()를 사용합니다.

구성할 매개변수는 installKeyPair()를 참고하세요. 이 기능은 인증서 관리를 위한 기존 API와 함께 작동합니다.

배포 시나리오

installKeyPair() 메서드가 없는 경우:

  • 사용자는 인증서에 대한 액세스 권한을 부여할 때마다 인증서 이름을 탭하고 허용을 탭해야 합니다.
  • 인증서를 설치할 때 사용자에게 메시지가 표시되며 인증서의 이름을 지정해야 합니다.

installKeyPair() 메서드를 사용합니다.

  • 사용자는 인증서에 대한 액세스 권한을 부여하려고 할 때마다 허용을 탭할 필요가 없습니다.
  • 사용자는 인증서의 이름을 바꿀 수 없습니다.
  • 관리자는 특정 인증서에 액세스해서는 안 되는 앱의 인증서를 차단할 수 있으므로 더 효과적으로 제어할 수 있습니다.

클라이언트 인증서 삭제

클라이언트 인증서에 액세스 권한을 부여한 후 installKeyPair()를 통해 설치된 클라이언트 인증서를 원격으로 삭제하려면 removeKeyPair()를 호출합니다.

기기 소유자 모드 또는 프로필 소유자 모드에서 실행되는 DPC 또는 위임된 인증서 설치 프로그램은 removeKeyPair()를 호출할 수 있습니다. 이렇게 하면 지정된 비공개 키 별칭에 설치된 인증서와 비공개 키 쌍이 삭제됩니다.

배포 시나리오

조직이 보다 안전한 형태의 클라이언트 인증서로 마이그레이션하는 경우 이 기능을 사용합니다. 관리자가 새 인증서를 배포하고 배포에 상당한 시간이 걸리는 경우 관리자는 이전이 완료된 후 지원 중단된 인증서를 취소할 수 있습니다.

보안 비밀번호 재설정

DPC는 사전 등록된 보안 토큰으로 변경을 승인하여 사용자의 비밀번호를 재설정할 수 있습니다. 기기 소유자 및 프로필 소유자는 보안 비밀번호 재설정 API를 호출하여 기기와 직장 프로필의 비밀번호를 각각 변경할 수 있습니다. 보안 비밀번호 재설정으로 resetPassword()가 다음 개선사항으로 대체됩니다.

  • DPC는 사용자가 기기에서 재부팅한 후 파일 기반 암호화를 사용하여 기기 또는 프로필을 잠금 해제하기 전에 비밀번호를 재설정할 수 있습니다.
  • Android 키 저장소는 비밀번호가 재설정된 후에도 사용자 인증 키를 보관합니다.

DPC 빌드가 Android 8.0 (API 수준 26) 이상을 타겟팅하는 경우 보안 비밀번호 재설정을 사용해야 합니다. resetPassword()를 호출하면 Android 8.0 이상을 타겟팅하는 DPC에서 SecurityException이 발생하므로 DPC를 업데이트해야 할 수도 있습니다.

토큰 설정 및 활성화

비밀번호를 재설정하기 전에 DPC에서 토큰을 설정하고 활성화해야 합니다. DPC가 토큰을 바로 사용하지 못할 수도 있으므로 IT 관리자가 사용해야 할 때가 되기 전에 토큰을 미리 설정합니다.

비밀번호 재설정 토큰은 암호적으로 강력한 임의 값이며 길이가 32바이트 이상이어야 합니다. 각 기기와 프로필의 토큰을 만듭니다. 생성된 토큰을 재사용하거나 공유하지 마세요.

토큰 또는 암호화된 토큰을 복호화하는 수단을 서버에 저장하는 것이 좋습니다. 사용자 인증 정보 암호화 저장소에 로컬로 토큰을 저장하면 사용자가 기기 또는 프로필을 잠금 해제할 때까지 DPC에서 비밀번호를 재설정할 수 없습니다. 토큰을 기기 암호화 저장소에 로컬로 저장하여 손상되면 공격자가 이 토큰을 사용하여 직장 프로필이나 기본 사용자의 액세스 권한을 얻을 수 있습니다.

DPC에서 새 토큰을 생성하거나 서버에서 토큰을 가져올 수 있습니다. 아래 예는 토큰 자체를 생성하여 서버에 보고하는 DPC를 보여줍니다.

Kotlin

val token = ByteArray(32)

// Generate a new token
val random = SecureRandom()
random.nextBytes(token)

// Set the token to use at a later date
val success: Boolean
success = dpm.setResetPasswordToken(DeviceAdminReceiver.getComponentName(context), token)

// Activate the token and update success variable...

// Store the token on a server
if (success) {
 sendTokenToServer(token)
}

Java

byte token[] = new byte[32]; // Minimum size token accepted

// Generate a new token
SecureRandom random = new SecureRandom();
random.nextBytes(token);

// Set the token to use at a later date
boolean success;
success = dpm.setResetPasswordToken(DeviceAdminReceiver.getComponentName(getContext()), token);

// Activate the token and update success variable ...

// Store the token on a server
if (success) {
 sendTokenToServer(token);
}

대부분의 경우 DPC는 토큰을 설정한 후에 활성화해야 합니다. 그러나 사용자에게 잠금 화면 비밀번호가 없으면 시스템에서 바로 토큰을 활성화합니다. 토큰을 활성화하려면 사용자에게 사용자 인증 정보를 확인하도록 요청합니다. DPC는 KeyguardManager 메서드 createConfirmDeviceCredentialIntent()를 호출하여 확인을 시작하는 Intent를 가져올 수 있습니다. 사용자 인터페이스에서 기기 사용자에게 인증을 요청하는 이유를 설명합니다. 아래 스니펫은 DPC에서 토큰을 활성화하는 방법을 보여줍니다.

Kotlin

// In your DPC, you'll need to localize the user prompt
val ACTIVATE_TOKEN_PROMPT = "Use your credentials to enable remote password reset"
val ACTIVATE_TOKEN_REQUEST = 1

// Create or fetch a token and set it in setResetPasswordToken() ...
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, ACTIVATE_TOKEN_PROMPT)

if (confirmIntent != null) {
 startActivityForResult(confirmIntent, ACTIVATE_TOKEN_REQUEST)
 // Check your onActivityResult() callback for RESULT_OK
} else {
 // Null means the user doesn't have a lock screen so the token is already active.
 // Call isResetPasswordTokenActive() if you need to confirm
}

Java

// In your DPC, you'll need to localize the user prompt
static final String ACTIVATE_TOKEN_PROMPT =
 "Use your credentials to enable remote password reset";
static final int ACTIVATE_TOKEN_REQUEST = 1;

// Create or fetch a token and set it in setResetPasswordToken() ...

KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
Intent confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(
  null, ACTIVATE_TOKEN_PROMPT);

if (confirmIntent != null) {
 startActivityForResult(confirmIntent, ACTIVATE_TOKEN_REQUEST);
 // Check your onActivityResult() callback for RESULT_OK
} else {
 // Null means the user doesn't have a lock screen so the token is already active.
 // Call isResetPasswordTokenActive() if you need to confirm
}

DPC에서 설정한 토큰을 기기를 재부팅하기 전에 활성화해야 합니다. Android는 활성화되지 않은 토큰을 메모리에 저장하며 재부팅 후에는 토큰을 유지하지 않습니다. 사용자가 토큰을 활성화하기 전에 기기를 재부팅하는 경우 DPC는 동일한 토큰을 다시 설정하거나 새 토큰을 생성할 수 있습니다.

DPC는 isResetPasswordTokenActive()를 호출하고 결과가 true인지 확인하여 토큰이 활성 상태인지 확인할 수 있습니다.

DPC가 토큰을 설정하고 활성화한 후에는 DPC가 토큰을 삭제하거나 교체하거나 기기가 초기화될 때까지 유효합니다. 토큰은 비밀번호와 별개이며 사용자가 비밀번호를 변경하거나 삭제해도 영향을 받지 않습니다.

토큰 삭제

clearResetPasswordToken()를 호출하여 DPC가 앞서 설정한 토큰을 삭제할 수 있습니다. 손상된 토큰을 취소하거나 비밀번호 재설정 기능을 삭제해야 할 수 있습니다. 아래 샘플은 DPC에서 이 작업을 실행하는 방법을 보여줍니다.

Kotlin

val dpm = getDpm()
val admin = DeviceAdminReceiver.getComponentName(requireActivity())

// Clear the token
if (!dpm.clearResetPasswordToken(admin)) {
 // Report the failure and possibly try later ...
}

Java

DevicePolicyManager dpm = getDpm();
ComponentName admin = DeviceAdminReceiver.getComponentName(getActivity());

// Clear the token
if (!dpm.clearResetPasswordToken(admin)) {
 // Report the failure and possibly try later ...
}

비밀번호 재설정

IT 관리자가 비밀번호를 재설정해야 하는 경우 resetPasswordWithToken()를 호출하고 DPC가 설정하고 활성화한 토큰을 전달합니다.

Kotlin

val token: ByteArray = getTokenFromServer()
val newPassword = "password"

try {
 val result: Boolean = dpm.resetPasswordWithToken(
 DeviceAdminReceiver.getComponentName(requireContext()),
 newPassword,
 token,
 0
 )

 if (result) {
 // The password is now 'password'
 } else {
 // Using 'password' doesn't meet password restrictions
 }
} catch (e: IllegalStateException) {
 // The token doesn't match the one set earlier.
}

Java

byte token[] = getTokenFromServer();
String newPassword = "password";

try {
 boolean result = dpm.resetPasswordWithToken(
  DeviceAdminReceiver.getComponentName(getContext()), newPassword, token, 0);

 if (result) {
 // The password is now 'password'
 } else {
 // Using `password` doesn't meet password restrictions
 }
} catch (IllegalStateException e) {
 // The token doesn't match the one set earlier.
}

새 비밀번호가 다음 제약 조건을 충족하지 않으면 resetPasswordWithToken()를 호출하면 false이 반환되고 비밀번호가 변경되지 않습니다.

  • 문자 수가 최소 비밀번호 길이 제약조건을 충족합니다. getPasswordMinimumLength()를 호출하여 IT 관리자가 길이 제약조건을 설정했는지 확인합니다.
  • 비밀번호 문자의 범위와 복잡성은 컴포지션 제약 조건을 충족합니다. getPasswordQuality()를 호출하여 IT 관리자가 컴포지션 제약조건을 설정했는지 확인합니다.

비밀번호 품질 제약 조건으로 비밀번호를 설정할 필요가 없으면 null 또는 빈 문자열을 resetPasswordWithToken()에 전달하여 비밀번호를 삭제할 수 있습니다.

작업 프로필 보안 인증 질문

프로필 소유자 모드에서 실행되는 DPC는 사용자가 직장 프로필에서 실행되는 앱의 보안 인증을 지정하도록 요구할 수 있습니다. 시스템은 사용자가 직장 앱을 열려고 할 때 보안 인증 질문을 표시합니다. 사용자가 보안 확인을 완료하면 시스템은 직장 프로필의 잠금을 해제하고 필요한 경우 직장 프로필을 복호화합니다.

직장 프로필 보안 인증 질문 작동 방식

  1. DPC가 ACTION_SET_NEW_PASSWORD 인텐트를 전송하면 시스템은 사용자에게 보안 인증 질문을 설정하라는 메시지를 표시합니다.
  2. DPC는 ACTION_SET_NEW_PARENT_PROFILE_PASSWORD 인텐트를 전송하여 사용자에게 기기 잠금을 설정하라는 메시지를 표시할 수도 있습니다.

DPC는 다른 기기 비밀번호 정책과는 다르게 작업 챌린지의 비밀번호 정책을 설정할 수 있습니다. 예를 들어 기기 보안 질문 응답의 최소 길이는 다른 비밀번호에 필요한 길이와 다를 수 있습니다. DPC는 setPasswordQuality()setPasswordMinimumLength()와 같은 일반적인 DevicePolicyManager 메서드를 사용하여 챌린지 정책을 설정합니다.

고려사항

  • DPC는 직장 프로필에서 비밀번호를 재설정할 수 있지만 기기 (개인) 비밀번호는 재설정할 수 없습니다. 사용자가 직장 비밀번호와 개인 비밀번호를 동일하게 설정하기로 선택하면 직장 프로필의 resetPassword()로 인해 비밀번호가 직장 프로필에서만 재설정되고 비밀번호는 기기 잠금 화면의 비밀번호와 동일하지 않습니다.
  • DPC는 setOrganizationColor()setOrganizationName()를 사용하여 작업 보안 질문을 위한 사용자 인증 정보 화면을 맞춤설정할 수 있습니다.
  • 기기 관리자는 resetPassword()를 사용하여 비밀번호를 지우거나 이미 설정된 비밀번호를 변경할 수 없습니다. 기기 관리자는 기기에 비밀번호, PIN 또는 패턴이 없는 경우에만 비밀번호를 설정할 수 있습니다.

자세한 내용은 getParentProfileInstance()DevicePolicyManager의 참조 문서를 확인하세요.