Skip to content

Most visited

Recently visited

navigation

시스템 권한

디자인 패턴

권한

동영상

Google I/O 2015—Android M 권한: 개발자를 위한 모범 사례

Android는 권한으로 구분되는 운영 체제이며, 여기서는 각 애플리케이션이 고유한 시스템 ID(Linux 사용자 ID 및 그룹 ID)를 사용하여 실행됩니다. 시스템의 각 부분은 고유한 ID로도 구분되어 있습니다. 그렇게 함으로써 Linux는 애플리케이션을 서로 간에 그리고 시스템으로부터 격리합니다.

추가 세부 수준의 보안 기능이 "권한" 메커니즘 통해 제공됩니다. 이 메커니즘에서는 특정 프로세스가 수행할 수 있는 특정 작업과 특정 데이터 조각에 대한 임시 액세스를 부여하기 위한 URI별 권한에 대한 제한을 적용합니다.

이 문서에서는 애플리케이션 개발자가 Android에서 제공하는 보안 기능을 어떻게 사용할 수 있는지에 대해 설명합니다. 추가 일반 Android 보안 개요는 Android 오픈소스 프로젝트에 나와 있습니다.

보안 아키텍처

Android 보안 아키텍처는 기본적으로 애플리케이션에 다른 애플리케이션, 운영 체제 또는 사용자에 안 좋은 영향을 미칠 수 있는 작업을 수행할 수 있는 권한이 없다는 것을 바탕으로 디자인되었습니다. 여기에는 사용자의 개인 데이터(예: 연락처 또는 이메일) 읽기/쓰기, 다른 애플리케이션 파일 읽기/쓰기, 네트워크 액세스 수행, 기기를 실행 상태로 유지 등이 포함됩니다.

Android 애플리케이션은 각각 하나의 프로세스 샌드박스에서 작업하기 때문에 애플리케이션은 리소스 및 데이터를 명시적으로 공유해야 합니다. 애플리케이션은 기본 샌드박스가 제공하지 않는 추가적인 기능에 대해 필요한 권한을 선언함으로써 이 작업을 수행합니다. 애플리케이션은 필요한 권한을 정적으로 선언하고 Android 시스템은 사용자에게 이에 대한 동의를 묻습니다.

애플리케이션 샌드박스는 애플리케이션을 빌드하는 데 사용된 기술에 종속되지 않습니다. 특히, Dalvik VM은 보안 경계가 아니며 모든 앱이 네이티브 코드를 실행할 수 있습니다(Android NDK 참조). 모든 유형의 애플리케이션(Java, 네이티브 및 하이브리드)이 동일한 방식으로 샌드박싱되며 각각 동일한 수준의 보안 기능을 가집니다.

애플리케이션 서명

모든 APK(.apk 파일)는 인증서로 서명되어야 하며, 이 인증서의 개인 키는 개발자가 유지합니다. 이 인증서는 애플리케이션의 작성자를 식별합니다. 인증서는 인증 기관이 서명할 필요가 없습니다. Android 애플리케이션이 자체 서명된 인증서를 사용하는 것은 전적으로 허용되는 일반적인 것입니다. Android에서 인증서의 용도는 애플리케이션 작성자를 구별하는 것입니다. 이를 통해 시스템은 애플리케이션에 서명 레벨 권한에 대한 액세스를 부여하거나 거부할 수 있으며 다른 애플리케이션과 동일한 Linux ID를 부여해달라는 애플리케이션 요청을 수락하거나 거부할 수 있습니다.

사용자 ID 및 파일 액세스

설치 시, Android는 각 패키지에 고유한 Linux 사용자 ID를 제공합니다. ID는 해당 기기에서 패키지의 수명 동안 일정하게 유지됩니다. 다른 기기에서는 동일한 패키지가 다른 UID를 가질 수 있습니다. 중요한 점은 각 패키지가 특정 기기에서 고유한 UID를 가진다는 것입니다.

보안이 프로세스 레벨에서 적용되며 패키지가 다른 Linux 사용자로 실행되어야 하기 때문에 두 개 패키지의 코드는 일반적으로 동일한 프로세스에서 실행될 수 없습니다. 각 패키지에 대한 AndroidManifest.xmlmanifest 태그에 sharedUserId 특성을 사용하여 패키지에 동일한 사용자 ID가 할당되도록 할 수 있습니다. 이렇게 함으로써 보안을 목적으로 두 패키지가 동일한 사용자 ID와 파일 권한을 갖는 동일한 애플리케이션으로 취급됩니다. 참고로, 보안을 유지하기 위해 동일한 서명으로 서명된(그리고 동일한 sharedUserId를 요청하는) 두 개의 애플리케이션에만 동일한 사용자 ID가 지정됩니다.

애플리케이션이 저장하는 데이터에만 해당 애플리케이션의 사용자 ID가 할당되고, 일반적으로 다른 패키지는 이 데이터에 액세스할 수 없습니다. getSharedPreferences(String, int), openFileOutput(String, int) 또는 openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory)를 사용하여 새 파일을 생성할 때는 MODE_WORLD_READABLE 및/또는 MODE_WORLD_WRITEABLE 플래그를 사용하여 다른 패키지가 파일을 읽고 쓸 수 있도록 허용할 수 있습니다. 이러한 플래그를 설정할 때 파일은 여전히 애플리케이션이 소유하지만, 해당 전역 읽기 및/또는 쓰기 권한은 기타 모든 애플리케이션이 파일을 볼 수 있도록 적절하게 설정되었습니다.

권한 사용

기본 Android 애플리케이션에는 기본적으로 이와 연결된 권한이 없습니다. 즉, 사용자 환경 및 기기에 저장된 모든 데이터에 안 좋은 영향을 미칠 수 있는 어떠한 작업도 수행할 수 없습니다. 기기의 보호되는 기능을 사용하려면 앱 매니페스트에 하나 이상의 <uses-permission> 태그를 포함해야 합니다.

예를 들어, 들어오는 SMS 메시지를 모니터링해야 하는 애플리케이션은 다음을 지정할 수 있습니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    ...
</manifest>

앱이 매니페스트에서 정상 권한(즉, 사용자 개인 정보 또는 기기 작업에 많은 위험이 되지 않는 권한)을 나열하는 경우 시스템이 자동으로 이러한 권한을 부여합니다. 앱이 매니페스트에서 위험한 권한(즉, 사용자 개인 정보 또는 기기의 정상 작업에 영향을 미칠 수 있는 권한)을 나열하는 경우 시스템이 이러한 권한을 명시적으로 부여하도록 사용자에게 요청합니다. Android가 요청을 수행하는 방법은 실행하는 시스템 버전과 앱에서 대상으로 지정하는 시스템 버전에 따라 다릅니다.

권한 오류로 인해 SecurityException이 애플리케이션에 발생하는 경우가 꽤 있습니다. 하지만, 이것이 모든 경우에 발생한다는 보장은 없습니다. 예를 들어, sendBroadcast(Intent) 메서드는 데이터가 각 수신기에 제공될 때 권한을 검사하고, 메서드 호출이 반환된 후에는 권한 오류가 있어도 예외가 수신되지 않습니다. 하지만, 거의 모든 경우 권한 오류가 시스템 로그에 출력됩니다.

Android 시스템에서 제공하는 권한은 Manifest.permission에서 확인할 수 있습니다. 모든 애플리케이션은 자체의 고유한 권한을 정의하고 적용할 수도 있으며, 따라서 이 목록이 가능한 모든 권한이 나열된 종합적인 목록은 아닙니다.

다음과 같은 경우 하나의 특정 권한이 프로그램 작업 동안 여러 위치에서 적용될 수 있습니다.

자동 권한 조정

시간이 지남에 따라 새 제한이 플랫폼에 추가될 수 있습니다. 이 경우, 특정 API를 사용하기 위해서는 앱이 이전에는 필요하지 않았던 권한을 요청해야 합니다. 기존 앱은 이러한 API에 대한 액세스를 자유롭게 사용할 수 있다고 간주하므로 Android는 새 권한 요청을 앱의 매니페스트에 적용하여 새 플랫폼 버전에 설치된 앱이 손상되는 것을 방지할 수 있습니다. Android는 targetSdkVersion 특성에 제공된 값에 따라 앱에 권한이 필요할 수 있을지 여부를 결정합니다. 값이 권한이 추가된 버전보다 낮을 경우 Android가 이 권한을 추가합니다.

예를 들어, WRITE_EXTERNAL_STORAGE 권한이 공유 저장소 공간에 대한 액세스를 제한하도록 API 레벨 4에 추가되었다고 가정합니다. 이 경우 targetSdkVersion이 3 이하이면 이 권한이 최신 버전의 Android에 설치된 앱에 추가됩니다.

주의: 권한이 앱에 자동으로 추가된 경우 앱이 실제적으로 권한을 필요로 하지 않을 수 있더라도 이러한 추가 권한이 Google Play의 앱 목록에 나열됩니다.

이를 방지하고 필요하지 않은 기본 권한을 제거하려면 항상 targetSdkVersion을 가능한 한 높게 업데이트해야 합니다. Build.VERSION_CODES 문서에서 각 릴리스에 추가된 권한을 확인할 수 있습니다.

정상 권한 및 위험한 권한

시스템 권한은 여러 보호 레벨로 나뉘어져 있습니다. 알아야 하는 가장 중요한 두 가지 보호 레벨은 정상 권한과 위험한 권한입니다.

권한 그룹

모든 위험한 Android 시스템 권한은 권한 그룹에 속합니다. 기기가 Android 6.0(API 레벨 23)을 실행 중이고 앱의 targetSdkVersion이 23 이상인 경우 앱이 위험한 권한을 요청할 때 다음 시스템 동작이 적용됩니다.

정상 권한과 앱에서 정의한 권한을 포함하여 어떠한 권한이든 권한 그룹에 속할 수 있습니다. 하지만, 권한 그룹은 권한이 위험한 경우에만 사용자 환경에 영향을 미칩니다. 정상 권한에 대해서는 권한 그룹을 무시할 수 있습니다.

기기가 Android 5.1(API 레벨 22) 이하를 실행하거나 앱의 targetSdkVersion이 22 이하인 경우, 시스템이 설치 시 권한을 부여하도록 사용자에게 요청합니다. 다시 한 번 설명하지만, 시스템은 사용자에게 개별 권한이 아니라 앱이 필요로 하는 권한 그룹만 알립니다.

표 1. 위험한 권한 및 권한 그룹.

권한 그룹 권한
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE

권한 정의 및 적용

자체적인 권한을 적용하려면 먼저 AndroidManifest.xml에서 하나 이상의 <permission> 요소를 사용하여 이러한 권한을 선언해야 합니다.

예를 들어, 해당 액티비티 중 하나를 시작할 수 있는 사용자를 제어해야 하는 애플리케이션은 다음과 같이 이 작업에 대한 권한을 선언할 수 있습니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp" >
    <permission android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
        android:label="@string/permlab_deadlyActivity"
        android:description="@string/permdesc_deadlyActivity"
        android:permissionGroup="android.permission-group.COST_MONEY"
        android:protectionLevel="dangerous" />
    ...
</manifest>

참고: 모든 패키지가 동일한 인증서로 서명되지 않은 경우에는 여러 패키지가 동일한 이름으로 권한을 선언할 수 있도록 시스템이 허용하지 않습니다. 패키지가 권한을 선언할 때, 사용자가 동일한 권한 이름을 사용하여 첫 번째 패키지와 동일한 인증서로 서명되지 않은 다른 패키지를 설치할 수 있도록 시스템이 허용하지 않습니다. 이름 충돌을 방지하려면 사용자 지정 권한의 이름을 도메인이 앞에 오는 스타일로 지정하는 것이 좋습니다(예: com.example.myapp.ENGAGE_HYPERSPACE).

protectionLevel 특성은 필수 항목입니다. 이 특성은 사용자에게 권한을 요구하는 애플리케이션을 알리는 방법이나 해당 권한을 보유할 수 있도록 허용되는 사용자를 시스템에 알립니다. 이에 대한 설명은 링크로 연결된 문서에 나와 있습니다.

android:permissionGroup 특성은 선택 항목이며, 시스템이 사용자에게 권한을 표시하는 데 도움을 주려는 경우에만 사용합니다. 대부분의 경우, 그룹을 직접 정의할 수 있더라도 이 특성을 표준 시스템 그룹(android.Manifest.permission_group에 나열되어 있음)으로 설정하는 것을 원할 것입니다. 기존 그룹을 사용하는 것이 사용자에게 표시되는 권한 UI를 단순화하므로 이 방법이 권장됩니다.

권한에 대해 레이블 및 설명을 모두 제공해야 합니다. 이는 사용자가 권한 목록(android:label)이나 단일 권한에 대한 세부 정보(android:description)를 볼 때 확인할 수 있는 문자열 리소스입니다. 레이블은 권한이 보호하는 기능의 주요 부분만 설명하는 몇 개 단어로 구성된 짧은 형식이어야 합니다. 설명은 권한 소유자가 수행할 수 있도록 해당 권한이 허용하는 작업을 설명하는 몇 개 문장으로 구성되어야 합니다. 설명을 두 개의 문장으로 구성하는 것이 규칙입니다. 첫 번째 문장은 권한을 설명하고, 두 번째 문장은 사용자에게 애플리케이션에 권한이 부여된 경우 잘못될 수 있는 항목의 유형을 경고합니다.

다음은 CALL_PHONE 권한에 대한 레이블 및 설명의 예시입니다.

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the application to call
    phone numbers without your intervention. Malicious applications may
    cause unexpected calls on your phone bill. Note that this does not
    allow the application to call emergency numbers.</string>

Settings 앱 및 쉘 명령어 adb shell pm list permissions를 사용하여 시스템에 현재 정의되어 있는 권한을 볼 수 있습니다. Settings 앱을 사용하려면 Settings > Applications로 이동합니다. 앱을 선택하고 아래로 스크롤하여 앱이 사용하는 권한을 확인합니다. 개발자의 경우, adb '-s' 옵션을 사용하면 사용자에게 권한이 표시되는 방법과 유사한 형태로 권한이 표시됩니다.

$ adb shell pm list permissions -s
All Permissions:

Network communication: view Wi-Fi state, create Bluetooth connections, full
Internet access, view network state

Your location: access extra location provider commands, fine (GPS) location,
mock location sources for testing, coarse (network-based) location

Services that cost you money: send SMS messages, directly call phone numbers

...

사용자 지정 권한 권장 사항

앱은 고유한 사용자 지정 권한을 정의한 후 <uses-permission> 요소를 정의하여 다른 앱에서 이러한 사용자 지정 권한을 요청할 수 있습니다. 하지만, 앱이 그렇게 하는 것이 필요한지 여부를 신중하게 평가해야 합니다.

AndroidManifest.xml에서 권한 적용

AndroidManifest.xml을 통해 시스템이나 애플리케이션의 전체 구성 요소에 대한 액세스를 제한하는 상위 수준의 권한을 적용할 수 있습니다. 이렇게 하려면 원하는 구성 요소에 대한 액세스를 제어하는 권한을 지명하여 이 구성 요소에 대해 android:permission 특성을 포함합니다.

Activity 권한(<activity> 태그에 적용됨)은 연결된 액티비티를 시작할 수 있는 사용자를 제한합니다. 이 권한은 Context.startActivity()Activity.startActivityForResult()가 실행되는 동안 검사됩니다. 호출자가 필요한 권한이 없을 경우 호출에서 SecurityException이 발생합니다.

Service 권한(<service> 태그에 적용됨)은 연결된 서비스를 시작하거나 바인딩할 수 있는 사용자를 제한합니다. 이 권한은 Context.startService(), Context.stopService()Context.bindService()가 실행되는 동안 검사됩니다. 호출자가 필요한 권한이 없을 경우 호출에서 SecurityException이 발생합니다.

BroadcastReceiver 권한(<receiver> 태그에 적용됨)은 연결된 수신자에 브로드캐스트를 전송할 수 있는 사용자를 제한합니다. 이 권한은 시스템이 지정된 수신자에 제출된 브로드캐스트를 제공하려고 시도하므로 Context.sendBroadcast()가 반환된 후에 검사됩니다. 따라서, 권한 오류가 발생해도 호출자에는 예외가 발생하지 않으며, 단지 인텐트만 제공하지 않게 됩니다. 같은 방법으로, 권한을 Context.registerReceiver()에 제공하여 프로그래밍 방식으로 등록된 수신자에게 브로드캐스트할 수 있는 사용자를 제어할 수 있습니다. 다르게는 Context.sendBroadcast()를 호출할 때 권한을 제공하여 브로드캐스트를 수신하도록 허용되는 BroadcastReceiver 객체를 제한할 수도 있습니다(아래 참조).

ContentProvider 권한(<provider> 태그에 적용됨)은 ContentProvider에서 데이터에 액세스할 수 있는 사용자를 제한합니다. (콘텐츠 제공자가 사용할 수 있는 URI 권한이라고 하는 중요한 추가 보안 기능이 있습니다. 이에 대해서는 뒷부분에서 설명합니다.) 다른 구성 요소와 달리, 두 가지 개별적인 권한 특성을 설정할 수 있습니다. android:readPermission은 제공자로부터 데이터를 읽을 수 있는 사용자를 제한하고, android:writePermission은 제공자에 데이터를 쓸 수 있는 사용자를 제한합니다. 참고로, 제공자가 읽기 및 쓰기 권한 모두를 사용하여 보호되는 경우, 쓰기 권한만 보유할 경우에는 제공자로부터 데이터를 읽을 수 없습니다. 먼저 제공자를 검색할 때 권한 검사가 수행되고(두 권한 중 하나라도 없는 경우 SecurityException이 발생함), 그 다음으로 제공자에서 작업을 수행할 때 검사가 수행됩니다. ContentResolver.query()를 사용하려면 읽기 권한이 있어야 하고, ContentResolver.insert(), ContentResolver.update(), ContentResolver.delete()를 사용하려면 쓰기 권한이 있어야 합니다. 이러한 경우 모두, 필요한 권한이 없으면 호출에서 SecurityException이 발생합니다.

브로드캐스트를 전송할 때 권한 적용

등록된 BroadcastReceiver에 인텐트를 전송할 수 있는 사용자에게 권한을 적용하는 경우(위의 설명 참조) 이외에, 브로드캐스트를 전송할 때 필요한 권한을 지정할 수도 있습니다. 권한 문자열을 사용하여 Context.sendBroadcast()를 호출함으로써 브로드캐스트를 수신하기 위해서는 수신기의 애플리케이션이 해당 권한을 보유해야 한다는 것을 요구해야 합니다.

수신기와 브로드캐스터 모두에 권한이 필요할 수 있습니다. 이 경우 두 권한 검사가 모두 통과해야만 인텐트가 연결된 대상에 제공됩니다.

기타 권한 적용

원하는 대로 세분화된 권한을 서비스에 대한 모든 호출에 적용할 수 있습니다. 이 작업은 Context.checkCallingPermission() 메서드를 사용하여 수행합니다. 원하는 권한 문자열을 사용하여 호출합니다. 그러면 권한이 현재 호출하는 프로세스에 부여되었는지 여부를 나타내는 정수가 반환됩니다. 이 방법은 일반적으로 서비스에서 게시된 IDL 인터페이스를 통해서나 다른 프로세스에서 지정하는 다른 방법을 통해 다른 프로세스에서 들어오는 호출을 실행하는 경우에만 사용할 수 있습니다.

권한을 검사하는 데 유용한 여러 가지 다른 방법이 있습니다. 다른 프로세스의 pid를 알고 있는 경우에는 Context 메서드 Context.checkPermission(String, int, int)를 사용하여 해당 pid에 대해 권한을 검사할 수 있습니다. 다른 애플리케이션의 패키지 이름을 알고 있는 경우에는 직접적인 PackageManager 메서드 PackageManager.checkPermission(String, String)을 사용하여 특정 패키지에 특정 권한이 부여되었는지 여부를 확인할 수 있습니다.

URI 권한

지금까지 설명한 표준 권한 시스템으로는 콘텐츠 제공자에 사용하는 데 충분하지 않은 경우가 많습니다. 콘텐츠 제공자는 읽기 및 쓰기 권한을 사용하여 자체적으로 보호하기를 원할 수 있으며, 이 경우 해당 직속 클라이언트는 다른 애플리케이션에서 작동하기 위해 특정 URI를 이러한 애플리케이션에 전달해야 합니다. 이에 대한 일반적인 예는 메일 애플리케이션의 첨부파일입니다. 메일은 민감한 사용자 데이터이므로 메일에 대한 액세스는 권한으로 보호되어야 합니다. 하지만, 이미지 첨부파일에 대한 URI가 이미지 뷰어에 제공된 경우 해당 이미지 뷰어가 모든 이메일에 액세스할 수 있는 권한을 가지고 있을 이유가 없으므로 이미지 뷰어가 이 첨부파일을 열 수 있는 권한을 가지고 있지 않을 것입니다.

이 문제를 해결할 수 있는 방법은 URI별 권한입니다. 액티비티를 시작하거나 결과를 액티비티에 반환할 때 호출자는 Intent.FLAG_GRANT_READ_URI_PERMISSION 및/또는 Intent.FLAG_GRANT_WRITE_URI_PERMISSION을 설정할 수 있습니다. 이 설정은 콘텐츠 제공자에서 인텐트에 해당하는 데이터에 액세스할 수 있는 권한이 있는지 여부에 상관없이 수신하는 액티비티 권한 액세스를 인텐트에 있는 특정 데이터 URI에 부여합니다.

이 메커니즘은 사용자 상호작용(첨부파일 열기, 목록에서 연락처 선택 등)이 세분화된 권한에 대한 임시 부여를 유도하는 일반적인 기능 스타일 모델을 허용합니다. 이는 애플리케이션에 필요한 권한을 동작과 직접적으로 관련이 있는 권한으로 줄이는 데 핵심적인 기능일 수 있습니다.

하지만 세분화된 URI 권한을 부여하려면 이러한 URI를 보유하는 콘텐츠 제공자와 협력해야 합니다. 콘텐츠 제공자가 이 기능을 구현하고 android:grantUriPermissions 특성 또는 <grant-uri-permissions> 태그를 통해 이 기능을 지원한다는 것을 선언할 것을 적극 권장합니다.

자세한 내용은 Context.grantUriPermission(), Context.revokeUriPermission()Context.checkUriPermission() 메서드에서 확인할 수 있습니다.

계속 읽기:

기능 요구사항을 암시하는 권한
일부 권한을 요청하는 것이 어떤 식으로 해당 하드웨어 또는 소프트웨어 기능을 포함하는 기기로 앱을 암묵적으로 제한하는지 설명하는 정보입니다.
<uses-permission>
앱의 필수 시스템 권한을 선언하는 매니페스트 태그에 대한 API 참조입니다.
Manifest.permission
모든 시스템 권한에 대한 API 참조입니다.

혹시 다음과 같은 내용에도 흥미가 있으신가요?

기기 호환성
여러 가지 유형의 기기에서 Android의 작동 방식과 앱을 각 기기에 맞춰 최적화하는 방법 또는 여러 가지 기기에 대해 앱의 가용성을 제한하는 방법 등에 관한 정보입니다.
Android 보안 개요
Android 플랫폼의 보안 모델에 대한 자세한 설명입니다.
This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.