Android Develoer Site : Security and Permissions
안드로이드는 각각의 어플리케이션과 시스템 내의 각 영역들이 자신의
공유한 프로세스 상에 실행되는 멀티 프로세스 시스템이다. 어플리케이션과
시스템 간의 대부분의 보안은 어플리케이션에 할당된 user id 혹은 group
id 오 가타은 표준 리눅스 설비를 통해 프로세스 레벨에서 강제된다. 보다
섬세한 추가적인 보안 기능은 퍼미션 메카니즘에 의해
제공된다. 퍼미션은 특정 프로세스가 수행할 수 있는 특정
오프레이션에 제약을 부가한다. 그리고 데이터의 특정 영역에 대한 임시적
접근을 부여하는 URI 별 퍼미션이 있다.
보안 아키텍쳐
안드로이드 보안 아티텍쳐의 핵심 다지인 핵심은, 디폴트로 어떤 어플리케이션도
다른 어플리케이션과 운영체제, 또는 사용자에게 나쁜 영향을 미칠 수 있는
임의의 오퍼레이션을 수행할 수 있는 퍼미션을 가지지 않는다는 것이다.
하나의 어플리케이션에 의해 요처된 퍼미션은 그 어플리케이션 내에
정적으로 선언된다. 그러므로 그 퍼미션은 그 어플리케이션의 설치전에 알
수 있으며, 그 후에는 변경될 수 없다.
Application Signing
모든 안드로이드 어플리케이션은 그것의 개발자가 보유한 개인키 인증서로
서명되어야 한다. 서명이 보안에 미치는 가장 중요한 사항들은 서명 기반의
퍼미션에 누가 접근 가능하며 누가 사용자 ID를 공유할 수 있는 지를
결정하는 것이다.
User ID 와 파일 접근
안드로이드 패키지 파일에는 그것 자신의 고유한 리눅스 유저 ID 가
부여된다. 이 유저 ID 는 어플리케이션이 디바이스에 설치될 때 할당되며,
그 디바이스에 그것이 존속하는 동안 변하지 않고 유지된다.
보안에 대한 강제는 프로세스 레벨에서 이루어지기 때문에, 임의의 두 개의
패키지 내의 코드는 일반적으로 동일한 프로세스에서 실핼될 수 없다. 서로
다른 패키지가 동일한 유저 ID 부여받기 위해서는 AndroidManifest.xml
의 manifest 태그의 sharedUserId attribute를 사용할 수 있다. 이를
사용한 경우 두 개의 패키지는 동일한 어플리케이션으로 간주되며 동일한
유저 ID 와 파일 퍼미션을 갖는다. 보안을 유지하기 위해, 동일한
서명을 가진 (그리고 동일한 sharedUserId를 요청하고 있는) 두 개의
어플리케이션에게만 동일한 유저 ID 가 부여된다.
어플리케이션에 의해 저장된 모든 데이터는 그 어플리케이션의 유저 ID 가
부여될 것이며, 일반적으로는 다른 패키지들에게는 접근 불가하다. 어떤
파일을 getSharedPreferences(String, int), openFileOutput(String,
int), openOrCreateDatabase(String, int,
QSLiteDatabase.CursorFactory)를 사용하여 생성할 경우, 이 파일에 대한
읽기/쓰기를 다른 패키지에 허용하기 위해 MODE_WORLD_READABLE 과
MODE_WORLD_WRITABLE 플래그를 사용할 수 있다.
퍼미션 사용하기
어플리케이션 설치 시점에, 어플리케이션에 의해 요청된 퍼미션은 해당
퍼미션을 선언하고 있는 어플리케이션의 서명 확인을 기반으로,
그리고/또는 사용자와의 상호작용에 기반해서 패키지 인스톨러에 의해 그
어플리케이션에 부여된다. 어플리케이션이 실행되는 동안에는 사용자와의
어떤 확인 절차도 이루어지지 않는다. 어플리케이션이 설치될 때 특정
퍼미션이 부여되어 해당 기능을 원하는 대로 사용할 수 있거나, 또는 그
퍼미션이 부여되지 않아 그 기능을 사용하려는 어떠한 시도도 사용자에게
알리지 않고 실패할 것이다. 종종 퍼미션 실패는 어플리케이션에 보안
예외 Security Exception가 발생하게 되지만 모든 곳에서 발생하는 것을
보장받지는 못한다. 그러나 거의 대부분의 경우에 퍼미션 실패는 시스템
로그에 기록될 것이다.
프로그램이 동작되는 동안에 다음 여러곳에서 특정 퍼미션이 강제될 수도
있다.
- 어플리케이션이 특정 함수 수행하는 것을 방지하기 위하여 시스템
내부로의 호출 시점.
- 어플리케이션이 다른 어플리케이션의 activity를 런치하는 것을 방지하기
위해, activity 시작하는 시점.
- 브로드캐스트 보내고 받는 시점.
- 컨텐트 프로바이저에 접근해서 동작하는 시점.
- 서비스를 바인딩하거나 시작하는 시점.
퍼미션 선언 및 강제
AndroidManifest.xml
permission : 퍼미션을 먼저 선언.
permissioinGroup : 선택사항. 시스템이 사용자에게 퍼미션을
표시하는 것을 돕기 위하여 사용.
label : 문자열 리소스. 사용자가 퍼미션 리스트를 볼 때 표시.
description : 문자열 리소스. 한 개의 퍼미션을 상세히 볼 때 표시.
AndroidManifest.xml 에서 퍼미션 강제하기
시스템이나 어플리케이션의 모든 컴포넌트에 대한 접근을 제약하는
상위계층의 퍼미션들은 AndroidManifest.xml 을 통해서 적용될 수
있다. 이를 위해 요구되는 것은 필요한 컴포넌트에 android:permission
attribute를 포함하고 그 컴포넌트에 대한 접근을 제어하기 위해 사용될
퍼미션 이름을 지정하는 것이 전부이다.
Activity
- 누가 해당 activity를 시작할 수 있는지를 제약.
Context.startActivity() 와 Activity.startActivityForResult()
함수 내에서 점검.
- 만약 호출자가 필요한 퍼미션을 가지고 있지 않으며, 보안 예외가
호출되는 곳에서 발생.
Service
- 누가 해당 서비스를 시작하거나 바인딩할 수 있는가를 제약.
Context.startService(), Context.stopService(),
Context.bindService() 함수 내에서 점검.
- 만약 호출자가 필요한 퍼미션을 가지고 있지 않다면, 보안 예외가
호출되는 곳에서 발생.
Receiver
- 누가 해당 리시버에게 브로드캐스트를 발송할 수 있는 가를 제약.
- 퍼미션은
Context.sendBroadcast() 가 리턴된 후, 시스템에 제출된
브로드캐스트를 주어진 리시버에 전달하기를 시도할 때
점검된다. 결론적으로 퍼미션 실패는 호출자에게 예외 결과를 발생시키지
않는다. 다만 퍼미션 실패는 인텐트를 전달하지 못할 뿐이다.
- 마찬가지로
Context.registerReceiver() 에 퍼미션 제공하여,
프로그램적으로 동록된 리시버에게 누가 브로드캐스트를 할 수 있는 가를
제어할 수 있다.
- broadcast send 시에 퍼미션 명명하는 경우에,
Context.sendBroadcast() 에 퍼미션 스트링과 함께 호출하는 경우에,
이 브로드캐스트 받기 위해서는 receiver application 은 해당 퍼미션을
반드시 가지고 있어야 한다. 이와 같이 broadcaster 와 receiver 양쪽
모두 퍼미션이 필요로 할 수도 있다.
Provider
- 누가 컨텐트 프로바이더에 있는 데이터에 접근할 수 있는가를 제약.
andriod:readPermission : 누가 프로바이더로부터 읽기를 할 수
있는가를 제약.
android:writePermission : 누가 그것에 쓰기를 할 수 있는가를 제약.
그 밖의 퍼미션 강제
- 임의의 정교한 퍼미션들이 하나의 서비스 안으로 호출이 일어날 때 강제될
수 있다.
Context.checkCallingPermission() 메쏘드에서 수행됨.
Context.checkPermission(String, int, int)
PackageManager.checkPermission(String, String)
URI 퍼미션
- Activity 시작시킬 때나 결과를 actitity 에 리턴할 때, 그것을 호출한
곳에서
Intent.FLAG_GRANT_READ_URI_PERMISSION 및/또는
Intent.FLAG_GRANT_WRITE_URI_PERMISSION 을 설정 가능 : 인텐트를
수신하는 activity 가 인텐트에 대응되는 컨텐트 프로바이더 내의 데이터
접근 퍼미션을 보유하고 있는 지와 상관없이, 그 액티비티에게 그 인텐트
내의 특정 데이터 URI 에 대한 접근 퍼미션을 부여한다.
Context.grantUriPermission()
Context.revokeUriPermission()
Context.checkUriPermission()