SafetyNet Verify Apps API

Google Play 서비스에서 제공하는 라이브러리인 SafetyNet Verify Apps API를 사용하면 앱이 기기의 앱 인증 기능과 프로그래매틱 방식으로 상호작용할 수 있어 잠재적으로 위험한 앱으로부터 기기를 보호합니다.

앱에서 금융 정보와 같은 민감한 사용자 데이터를 처리하는 경우 사용자의 기기가 악성 앱으로부터 보호되고 있으며 내 앱을 가장하거나 다른 악성 작업을 실행할 수 있는 앱이 없는지 확인하는 것이 중요합니다. 기기의 보안이 최소 보안 상황을 충족하지 않으면 자체 앱 내에서 기능을 사용 중지하여 사용자에게 미치는 위험을 줄일 수 있습니다.

Google은 Android 생태계를 최대한 안전하게 만들려는 지속적인 노력의 일환으로 Android 앱의 동작을 모니터링하고 프로파일링합니다. 앱 인증 기능이 잠재적으로 위험한 앱을 감지하면 이 앱을 설치한 모든 사용자는 앱을 즉시 제거하라는 알림을 받습니다. 이 프로세스는 이러한 사용자의 보안 및 개인 정보 보호를 강화합니다.

SafetyNet Verify Apps API를 사용하면 이 기능을 활용하여 앱의 데이터를 보호할 수 있습니다. 이 API를 사용하면 사용자의 기기가 앱 인증 기능으로 보호되는지 여부를 확인하고, 이 기능을 아직 사용하지 않는 사용자에게 이 기능의 보호를 선택하도록 권장하고, 기기에 설치되어 있는 알려진 잠재적으로 위험한 앱을 식별할 수 있습니다.

추가 서비스 약관

SafetyNet API에 액세스하거나 SafetyNet API를 사용하면 Google API 서비스 약관 및 다음 Verify Apps API 서비스 약관에 동의하는 것으로 간주됩니다. SafetyNet API에 액세스하기 전에 모든 관련 약관 및 정책을 자세히 읽고 숙지하시기 바랍니다.

Verify Apps API 서비스 약관

잠재적으로 위험한 앱을 식별하는 앱을 분석하면 결과에 거짓양성과 거짓음성이 모두 나올 수 있습니다. 이 API 세트에서 반환된 결과(또는 결과 없음)는 Google이 파악한 한도 내에서 제시됩니다. 개발자는 이 SafetyNet API 세트에서 반환되는 결과가 때로는 정확성이 보장되지 않는다는 점을 인정하고 이해합니다.

SafetyNet API 종속 항목 추가

Verify Apps API를 사용하기 전에 프로젝트에 SafetyNet API를 추가하세요. Android 스튜디오를 사용한다면 이 종속 항목을 앱 수준 Gradle 파일에 추가하세요. 자세한 내용은 SafetyNet API 설정을 참고하세요.

앱 인증 사용 설정

SafetyNet Verify Apps API에는 앱 인증 기능을 사용 설정하는 두 가지 방법이 있습니다. isVerifyAppsEnabled()를 사용하여 앱 인증이 사용 설정되어 있는지 여부를 확인할 수 있으며 enableVerifyApps()를 사용하여 앱 인증 사용 설정을 요청할 수 있습니다.

이 두 가지 방법의 차이를 보면, isVerifyAppsEnabled()는 앱 인증 기능의 현재 상태를 보고하고 enableVerifyApps()는 사용자에게 앱 인증 기능 사용에 동의하도록 명시적으로 요청합니다. 앱이 보안 기반 결정을 내리기 위해 앱 인증 기능의 상태를 인지하도록 하려면 앱이 isVerifyAppsEnabled()를 호출해야 합니다. 그러나 앱이 기기에 설치되어 잠재적으로 위험한 앱을 나열할 수 있게 하려면 enableVerifyApps()를 대신 호출해야 합니다.

앱 인증이 사용 설정되었는지 여부 확인

비동기 isVerifyAppsEnabled() 메서드를 사용하면 사용자가 앱 인증 기능에 등록되었는지 앱에서 확인할 수 있습니다. 이 메서드는 VerifyAppsUserResponse 객체를 반환하며, 이 객체에는 사용자가 앱 인증 기능과 관련하여 취한 모든 조치(사용 설정 포함)에 관한 정보가 포함되어 있습니다.

다음 코드 스니펫은 이 메서드와 관련된 콜백을 만드는 방법을 보여줍니다.

Kotlin

SafetyNet.getClient(this)
        .isVerifyAppsEnabled
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                if (task.result.isVerifyAppsEnabled) {
                    Log.d("MY_APP_TAG", "The Verify Apps feature is enabled.")
                } else {
                    Log.d("MY_APP_TAG", "The Verify Apps feature is disabled.")
                }
            } else {
                Log.e("MY_APP_TAG", "A general error occurred.")
            }
        }

Java

SafetyNet.getClient(this)
    .isVerifyAppsEnabled()
    .addOnCompleteListener(new OnCompleteListener<VerifyAppsUserResponse>() {
        @Override
        public void onComplete(Task<VerifyAppsUserResponse> task) {
            if (task.isSuccessful()) {
                VerifyAppsUserResponse result = task.getResult();
                if (result.isVerifyAppsEnabled()) {
                    Log.d("MY_APP_TAG", "The Verify Apps feature is enabled.");
                } else {
                    Log.d("MY_APP_TAG", "The Verify Apps feature is disabled.");
                }
            } else {
                Log.e("MY_APP_TAG", "A general error occurred.");
            }
        }
    });

앱 인증 사용 설정 요청

비동기 enableVerifyApps() 메서드를 사용하면 앱에서 사용자에게 앱 인증 기능을 사용 설정하도록 요청하는 대화상자를 호출할 수 있습니다. 이 메서드는 VerifyAppsUserResponse 객체를 반환하며, 이 객체에는 사용자가 앱 인증 기능과 관련하여 취한 모든 조치(사용 설정하도록 동의했는지 여부 포함)에 관한 정보가 포함되어 있습니다.

다음 코드 스니펫은 이 메서드와 관련된 콜백을 만드는 방법을 보여줍니다.

Kotlin

SafetyNet.getClient(this)
        .enableVerifyApps()
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                if (task.result.isVerifyAppsEnabled) {
                    Log.d("MY_APP_TAG", "The user gave consent to enable the Verify Apps feature.")
                } else {
                    Log.d(
                            "MY_APP_TAG",
                            "The user didn't give consent to enable the Verify Apps feature."
                    )
                }
            } else {
                Log.e("MY_APP_TAG", "A general error occurred.")
            }
        }

Java

SafetyNet.getClient(this)
    .enableVerifyApps()
    .addOnCompleteListener(new OnCompleteListener<VerifyAppsUserResponse>() {
        @Override
        public void onComplete(Task<VerifyAppsUserResponse> task) {
            if (task.isSuccessful()) {
                VerifyAppsUserResponse result = task.getResult();
                if (result.isVerifyAppsEnabled()) {
                    Log.d("MY_APP_TAG", "The user gave consent " +
                          "to enable the Verify Apps feature.");
                } else {
                    Log.d("MY_APP_TAG", "The user didn't give consent " +
                          "to enable the Verify Apps feature.");
                }
            } else {
                Log.e("MY_APP_TAG", "A general error occurred.");
            }
        }
    });

이 메서드를 사용할 때 앱에는 하나 이상의 비정상적인 상황이 발생할 수 있습니다.

  • 이미 앱 인증 기능이 사용 설정되어 있다면 대화상자가 나타나지 않으며 API는 사용자가 이 기능을 사용 설정하도록 동의한 것처럼 작동합니다.
  • 사용자가 대화상자에서 벗어나서 이동하면 대화상자가 사라지고 API는 사용자가 이 기능을 사용 설정하도록 동의하지 않았다고 가정합니다.
  • 개발자의 앱 및 다른 앱이 동시에 이 메서드를 호출하면 대화상자가 한 개만 나타나고 모든 앱이 메서드에서 동일한 반환 값을 수신합니다.

설치된 앱 중 잠재적으로 위험한 앱 나열

비동기 listHarmfulApps() 메서드를 사용하면 사용자가 기기에 설치한 알려진 잠재적으로 위험한 앱의 목록을 가져올 수 있습니다. 앱이 적절한 조치를 취할 수 있도록 이 목록에는 식별된 잠재적으로 위험한 앱의 카테고리가 포함됩니다.

다음 코드 스니펫은 이 메서드와 관련된 콜백을 만드는 방법을 보여줍니다.

Kotlin

SafetyNet.getClient(this)
        .listHarmfulApps()
        .addOnCompleteListener { task ->
            Log.d(TAG, "Received listHarmfulApps() result")

            if (task.isSuccessful) {
                val result = task.result
                val scanTimeMs = result.lastScanTimeMs

                val appList = result.harmfulAppsList
                if (appList?.isNotEmpty() == true) {
                    Log.e("MY_APP_TAG", "Potentially harmful apps are installed!")

                    for (harmfulApp in appList) {
                        Log.e("MY_APP_TAG", "Information about a harmful app:")
                        Log.e("MY_APP_TAG", "  APK: ${harmfulApp.apkPackageName}")
                        Log.e("MY_APP_TAG", "  SHA-256: ${harmfulApp.apkSha256}")

                        // Categories are defined in VerifyAppsConstants.
                        Log.e("MY_APP_TAG", "  Category: ${harmfulApp.apkCategory}")
                    }
                } else {
                    Log.d("MY_APP_TAG", "There are no known potentially harmful apps installed.")
                }
            } else {
                Log.d(
                        "MY_APP_TAG",
                        "An error occurred. Call isVerifyAppsEnabled() to ensure that the user "
                                + "has consented."
                )
            }
        }

Java

SafetyNet.getClient(this)
    .listHarmfulApps()
    .addOnCompleteListener(new OnCompleteListener<HarmfulAppsResponse>() {
        @Override
        public void onComplete(Task<HarmfulAppsResponse> task) {
            Log.d(TAG, "Received listHarmfulApps() result");

            if (task.isSuccessful()) {
                HarmfulAppsResponse result = task.getResult();
                long scanTimeMs = result.getLastScanTimeMs();

                List<HarmfulAppsData> appList = result.getHarmfulAppsList();
                if (appList.isEmpty()) {
                    Log.d("MY_APP_TAG", "There are no known " +
                          "potentially harmful apps installed.");
                } else {
                    Log.e("MY_APP_TAG",
                          "Potentially harmful apps are installed!");

                    for (HarmfulAppsData harmfulApp : appList) {
                        Log.e("MY_APP_TAG", "Information about a harmful app:");
                        Log.e("MY_APP_TAG",
                              "  APK: " + harmfulApp.apkPackageName);
                        Log.e("MY_APP_TAG",
                              "  SHA-256: " + harmfulApp.apkSha256);

                        // Categories are defined in VerifyAppsConstants.
                        Log.e("MY_APP_TAG",
                              "  Category: " + harmfulApp.apkCategory);
                    }
                }
            } else {
                Log.d("MY_APP_TAG", "An error occurred. " +
                      "Call isVerifyAppsEnabled() to ensure " +
                      "that the user has consented.");
            }
        }
    });