IT_Programming/Android_Java

[펌] 안드로이드 – 악성 앱을 막기 위한 새로운 권한, REQUEST_INSTALL_PACKAGE

JJun ™ 2017. 11. 14. 16:05



 출처

 : https://blog.uzuki.live/안드로이드-악성-앱을-막기-위한-새로운-권한-request_install_package/

 : https://android-developers.googleblog.com/2017/08/making-it-safer-to-get-apps-on-android-o.html

 : https://developers-kr.googleblog.com/2017/09/making-it-safer-to-get-apps-on-android-o.html



보통 안드로이드 기기의 정보를 탈취하기 위해서는 앱을 설치하고나서 그 앱이 기기 정보나 개인정보를
무단 수집, 서버로 보내는 형태를 많이 사용합니다.

이는 안드로이드의 장점 중 하나인 앱의 자유로운 설치가 단점으로 돌아온 대표적인 예시 중 하나입니다.

그래서 2017년 초에 구글은 Google Play Protect 를 사용하여 구글 플레이 스토어 전역에 있는 PHA(Potentially Harmful App, 잠재적 악성 앱) 의 비율을 줄여나갔습니다.

하지만 안드로이드 앱을 다운받을 수 있는 곳은 플레이 스토어 단 한 곳이 아닙니다. 2016년 연례 안드로이드 보안 보고서 의 일부에는 플레이 스토어에 출시되어 있는 의 비율은 줄었지만 비공식 마켓 등에서 배포되는 PHA는 여전히 남아있습니다.

그래서 구글은 안드로이드 8.0부터 플레이 스토어 이외의 곳에서 다운받은 앱을 설치하도록 하는 행동을 실행할 경우, 새로운 권한을 사용하도록 하였습니다.

그것이 바로 REQEUST_INSTALL_PACAKGE 권한입니다.

 

아래는 안드로이드 개발자 블로그 ‘Making it safer to get apps on Android O’ 글의 일부 번역입니다.


 

안드로이드 Oreo (8.0) 부터 새롭게 나온 ‘Install Unknown apps’ 권한은 알 수 없는 소스에서 앱을 안전하게 설치할 수 있도록 도와줍니다.

왼쪽: (안드로이드 8.0 전) 시스템 업데이트로 가장한 PHA

오른쪽: (안드로이드 8.0 이상) PHA가 설치되기 전 먼저 권한을 부여해야 합니다.


이 권한은 다른 런타임 권한처럼 설치할 때 권한을 띄우며 유저가 해당 소스를 사용해 앱을 설치할 수 있기 전에 권한을 획득하도록 합니다.

사용자가 안드로이드 Oreo 또는 이상의 버전을 사용중일 때, 악성 다운로더는 사용자에게 어떠한 앱을 설치하도록 속일 수 없습니다.

 

유저는 언제든지 알 수없는 앱 설치를 허용 한 앱을 검토 할 수 있습니다.
권한 부여 프로세스를 쉽게하기 위해 앱 개발자는 사용자를 권한 화면으로 안내 할 수 있습니다.


이 새로운 권한은 유저에게 신뢰할 수 있는 소스에 대한 투명성, 제어 및 간소화된 프로세스를 제공합니다.

설정 앱에서는 유저가 신뢰할 수 있는 소스의 리스트를 표시하며, 유저는 언제나 이 소스에 대해 권한을 취소할 수 있습니다.


사용하려면?

이 권한을 사용하려면, 우선 앱의 targetSdkVersion을 26 이상으로 하고, 매니페스트에 REQUEST_INSTALL_PACKAGE를 선언하면 됩니다.

  1. <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

권한을 사용하지 않은 앱은 다른 앱을 설치할 수 없게 됩니다.

개발자는 앱을 설치할 수 있도록 설정하는 화면을 ACTION_MANAGE_UNKNOWN_APP_SOURCES 인텐트 액션을 통해 표시할 수 있으며,  PackageManager.canRequestPackageInstalls() 를 사용하여 권한 상태를 판단할 수 있습니다.



 예)

 Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);

intent.setData(Uri.parse("package:" + context.getPackageName()));

 * 출처 : https://stackoverflow.com/a/46344082




    

 * 출처

 : https://github.com/Microsoft/AppCenter-SDK-Android/blob/66e34235306a465f82eda30c00667dc4431bf104/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/Distribute.java   

    /**
     * Navigate to security settings or application settings on Android O.
     *
     * @param releaseDetails release details to check for state change.
     */
    private synchronized void goToUnknownAppsSettings(ReleaseDetails releaseDetails) {
        Intent intent;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
            intent.setData(Uri.parse("package:" + mForegroundActivity.getPackageName()));
        } else {
            intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
        }
        try {
            /*
             * We can't use startActivityForResult as we don't subclass activities.
             * And a no U.I. activity of our own must finish in onCreate,
             * so it cannot receive a result.
             */
            mForegroundActivity.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            /* on some devices, it's not possible, user will do it by himself. */
            AppCenterLog.warn(LOG_TAG, "No way to navigate to secure settings on this device automatically");
            /* Don't pop dialog until app restarted in that case. */
            if (releaseDetails == mReleaseDetails) {
                completeWorkflow();
            }
        } 

}


 * 출처

 : https://github.com/Microsoft/AppCenter-SDK-Android/blob/66e34235306a465f82eda30c00667dc4431bf104/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/InstallerUtils.java

    /**
     * Check whether user enabled installation via unknown sources.
     *
     * @param context any context.
     * @return true if installation via unknown sources is enabled, false otherwise.
     */
    @SuppressWarnings("deprecation")
    static boolean isUnknownSourcesEnabled(@NonNull Context context) {
        /*
         * on Android 8 with applications targeting lower versions,
         * it's impossible to check unknown sources enabled: using old APIs will always return true
         * and using the new one will always return false,
         * so in order to avoid a stuck dialog that can't be bypassed we will assume true.
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O || context.getPackageManager().canRequestPackageInstalls();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return INSTALL_NON_MARKET_APPS_ENABLED.equals(Settings.Global.getString(context.getContentResolver(), Settings.Global.INSTALL_NON_MARKET_APPS));
        } else {
            return INSTALL_NON_MARKET_APPS_ENABLED.equals(Settings.Secure.getString(context.getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS));
        }
    }



☞ Google Play에서 배포되는 앱에는 Play 정책이 적용된다는 점에 유의하세요.
    대부분의 경우 앱 내에서 다른 앱을 직접 다운로드하거나 설치하는 동작은 허용되지 않으며,
    대신 Play Store의 앱 목록을 바로가는 
딥 링크를 제공해야 합니다.
    (출처: https://developers-kr.googleblog.com/2017/09/making-it-safer-to-get-apps-on-android-o.html)


마무리

이 권한을 사용해서 적어도 사용자를 속이고 설치하는 앱의 갯수는 줄어들거라 봅니다.

물론 언제나 사용자가 허용한다면 통하지는 않겠지만 적어도 사용자에게 이 앱은 알 수 없는 곳에서 다운받은 것이니 조심하라 라는 표시를 할 수 있으면 충분하다고 생각됩니다.