본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[android 보안] 안드로이드 보안 모델 #2

by 돼지왕왕돼지 2018. 4. 15.

[android 보안] 안드로이드 보안 모델 #2


/data/system/packages.list, /data/system/packages.xml, /data/system/users/<사용자 아이디>/, adb, androidmanifest.xml, android_filesystem_config.h, apk, app uid, app_, authorization rule, baseband, DAC, Discretionary Access Control, enforcing mode, gid, IPC, jar, jar 패키지 포맷 확장, MAC, Mandatory Access Control, MODE_WORLD_READABLE, MODE_WORLD_WRITEABLE, offset, OTA, over the air, packages.list, permission protection level, permissive mode, policy, requested permission, required permision, Same Origin Policy, sandvox, seandroid, secucrityexception, security enhanced linux, security enhancement for android, seinfo, selinux, Shared User ID, UID, uid 0, uid 1000, uid gid, uY_a, [android 보안] 안드로이드 보안 모델 #2, 강제 접근 제어, 계정 데이터, 공유 사용자 아이디, 공유 사용자 아이디 추가, 구글, 권한, 다중 사용자 지원, 동일 출처 정책, 동일 프로세스, 동일한 리소스, 동일한 코드 서명, 디렉토리 경로, 디바이스 제조사, 디버깅 가능 플래그, 런타임 오류, 모뎀, 모듈화, 무선, 베이스 밴드, 보안 강화 리눅스, 복구 os, 부트 로더, 사용자 고유 설정 정보, 사용자 공간 라이브러리, 사용자 아이디, 설치된 앱 목록, 시스템 uid, 시스템 데몬, 시스템 앱, 시스템 업데이트, 실행 파일 공유, 안드로이드 보안 모델, 앱 id, 앱 샌드박스, 오픈 소스 안드로이드, 요청 권한, 임의 접근 제어, 전용 디렉터리, 전용 프로세스, 접근 권한을 설정해서 전달, 정책, 처음 설계시부터, 커널 드라이버, 코드 서명과 플랫폼 키, 통신사, 파일 공유, 패키지명, 플랫폼 키, 필수 권한, 핵심 시스템 데몬, 허용 모드, 홈 화면 파라미터

1.2. 안드로이드 보안 모델


-

시스템의 나머지 부분과 마찬가지로 안드로이드의 보안 모델은 리눅스 커널이 제공하는 보안기능을 활용한다.

다중 사용자 시스템인 리눅스는 프로세스들을 서로 격리시키듯이 사용자 리소스들도 서로 격리시킬 수 있다.



-

전통적인 리눅스에서는 시스템에 로그인해서 셸을 통해 명령을 실행하는 실제 사용자나 백그라운드에서 실행되는 시스템 서비스에 전용  UID 를 부여했다.

그러나 안드로이드는 스마트폰을 위해 만들어졌고, 또 모바일폰은 개인용 기기이기 때문에 시스템에 여러 사용자를 등록할 필요가 없다.

사용자는 스마트폰의 소유자를 한 명으로 간주하고, 대신 UID 는 앱을 구분하는 용도로 사용한다.



** 1.2.1. 앱 샌드박스


-

안드로이드는 앱을 설치할 때 각 앱에 “앱 ID” 라고 불리는 고유한 UID 를 자동으로 할당하고, 해당 UID 로 실행되는 전용 프로세스 내에서 앱을 실행한다.

그리고 각 앱은 자신만이 읽고 쓸 수 있는 전용 디렉터리를 부여받는다.

따라서 앱은 프로세스 수준(각 앱을 별도의 전용 프로세스에서 실행한다)과 파일 수준(개별 데이터 디렉터리)에서 샌드박스된다.



-

시스템 데몬과 시스템 앱은 잘 정의된 고정 UID 로 실행되고 극히 일부만 루트 사용자( UID 0 ) 로 실행된다.

시스템 UID 는 android_filesystem_config.h 헤더 파일에 정적으로 정의되어 있다.

시스템 서비스의 UID 는 1,000번부터 시작하며 1,000번은 시스템( AID_SYSTEM ) 사용자다.



-

자동으로 생성되는 앱 UID 는 10000 (AID_APP) 부터 시작하며, 해당 사용자명은 app_XXX, 혹은 다중 사용자를 지원하는 안드로이드 버전에서는 uY_aXXX 로 할당한다.

여기에서 XXX 는 AID_APP 에서 시작하는 오프셋 값이며, Y 는 안드로이드 사용자 아이디( UID 와는 다르다 ) 다.


예를 들어 10037 UID 는 u0_a37 사용자명에 대응된다.



-

MODE_WORLD_READABLE 과 MODE_WORLD_WRITEABLE 플래그로 파일을 생성하면 파일의 S_IROTH 와 S_IWOTH 접근 비트가 설정되어 다른 앱이 이 파일에 직접 접근할 수 있다.

그렇지만 파일을 직접 공유하는 방식은 권장하지 않으며, 안드로이드 버전 4.2부터는 이 플래그들의 사용을 억제하고 있다.



-

앱 UID 는 /data/system/packages.xml 파일(공식 데이터 원천)에 있는 다른 패키지 메타 데이터와 함께 관리되며 /data/system/packages.list 파일에도 저장된다.


packages.list 의 첫 번째 필드는 패키지명, 두번째는 앱에 할당된 UID, 세 번째는 디버깅 가능 플래그(1이면 디버깅 가능), 네 번째는 앱의 데이터 디렉토리 경로, 다섯 번째는 SELinux 가 사용하는 seinfo 레이블이다.

마지막은 앱을 실행할 때 부여할 GID 목록이다.

각 GID 는 안드로이드 권한에 연결되어 있으며, GID 목록은 앱에 부여한 권한에 따라 생성된다.



-

공유 사용자 아이디(Shared User ID)를 사용하는 경우에는 여러 앱이 동일한 UID 를 사용할 수 있다.

공유 사용자 아이디를 사용하면 파일을 공유할 수 있고 심지어 동일 프로세스에서 실행되기도 하는데, 모듈화하기 위해 분할한 여러 패키지에서 동일한 리소스를 사용해야 할 경우가 많은 시스템 앱에서 주로 사용한다.



-

공유 사용자 아이디 기능을 시스템 앱이 아닌 일반 앱에는 권장하지 않지만, 서드파티 앱에서는 사용할 수 있다.

동일한 UID 를 공유하려면 앱을 동일한 코드 서명 키로 서명해야 한다.

그리고 이미 설치된 앱의 새로운 버전에 공유 사용자 아이디를 추가하려면 UID 를 바꿔야 하는데, 이는 시스템이 허용하지 않으므로 기존 앱이 공유 사용자 아이디를 갖게 할 수는 없다.

따라서 공유 사용자 아이디를 사용하려면 처음 설계할 때부터 공유 사용자 아이디를 지원하도록 만들어야 한다.




* 1.2.2. 권한


-

앱을 설치할 때 안드로이드는 요청된 권한들을 검사하고 이를 허용할지 여부를 결정한다.

일부 권한은 미리 설치된 기본 앱이나 OS 와 동일한 키로 서명된 앱에만 부여할 수 있다.

서드파티 앱은 커스텀 권한을 직접 정의하고 권한 보호 수준(Permission Protection Level)으로 제약을 정의해 서비스와 리소스를 제공하는 제작자가 만든 앱들만 이 서비스와 리소스에 접근할 수 있게 한다.




* 1.2.3. IPC


-

안드로이드는 IPC 를 구현하기 위해 커널 드라이버와 사용자 공간 라이브러리를 함께 사용한다.



-

요청 권한(Requested Permission)과 마찬가지로 필수 권한(Required Permission)도 AndroidManifest.xml 파일에서 선언할 수 있다.

컴포넌트별 권한도 바인더에서 가져온 호출자 UID 를 참조해 동적으로 구현할 수 있다.


시스템은 패키지 데이터베이스에서 피호출자가 요구하는 권한을 파악하고, 패키지명과 호출자 UID 를 비교해 호출자에게 부여된 권한을 가져온다.

요구하는 권한을 호출자가 갖고 있으면 호출은 성공하며, 그렇지 않을 때에는 시스템에서 SecurityException 예외를 발생시킨다.




* 1.2.4. 코드 서명과 플랫폼 키


-

안드로이드 APK 파일은 자바 JAR 패키지 포맷을 확장한 것이므로 코드 서명 기법도 JAR 서명 기법에 기반을 두고 있다.

안드로이드는 동일 개발자만 앱을 업데이트할 수 있게 하고, 앱 간의 신뢰 관계를 설정하기 위해 APK 서명을 이용한다.

( 이를 동일 출처 정책(Same Origin Policy) 라고 한다. )


이 보안 기능은 모두 현재 설치된 타깃 앱의 서명 인증서와 업데이트할 앱의 인증서를 비교해 구현한다.



-

시스템 앱은 여러 플랫폼 키로 서명된다.

동일한 플랫폼 키로 서명된 시스템 컴포넌트끼리는 리소스를 공유하고 같은 프로세스 안에서 실행된다.

플랫폼 키는 디바이스 제조사, 통신사, 구글(넥서스에 한해), 오픈 소스 안드로이드를 직접 빌드해 설치한 사용자 등 특정 디바이스에 설치된 안드로이드 버전을 유지하는 사람 누구나 생성하고 관리할 수 있다.




* 1.2.5. 다중 사용자 지원


-

각 사용자에는 0번부터 시작하는 고유한 사용자 아이디가 부여되며, /data/system/users/<사용자 아이디>/ 밑에 자신만의 전용 데이터 디렉터리(사용자의 시스템 디렉터리라고 한다.)를 갖는다.

이 디렉터리에는 홈 화면 파라미터, 계정 데이터, 현재 설치된 앱 목록과 같은 사용자 고유 설정 정보가 저장된다.

앱 실행 파일은 여러 사용자가 공유하지만 각 사용자는 자신만의 고유한 앱 데이터 디렉터리를 갖는다.




* 1.2.6. SELinux


-

전통적인 안드로이드 보안 모델은 앱에 부여된 UID 와 GID 에 많이 의존한다.



-

앱이 자신의 파일에 아무나 접근할 수 있도록 허용하는 것을 막지는 않는다.

마찬가지로 악성 앱이 과도하게 접근이 허용된 시스템 파일이나 지역 소켓을 사용하는 것도 막지 않는다.

사실 앱이나 시스템 파일에 부적절하게 할당된 권한은 수많은 안드로이드 취약점의 원천이 되어 왔다.


임의 접근 제어(Discretionary Access Control, DAC)라고 알려진, 리눅스가 사용하는 기본 접근 제어 모델을 사용하면 이런 취약점을 피할 수 없다.

“임의” 라는 말은 사용자가 일단 어떤 리소스에 접근할 수 있으면 그 리소스에 대한 접근 권한을 자신의 재량으로 임의 설정해 다른 사용자에게 전달할 수 있음을 뜻한다.

심지어 모든 사용자가 읽을 수 있도록 설정할 수도 있다.


이와 반대로 강제 접근 제어(Mandatory Access Control, MAC) 는 리소스에 대한 접근이 시스템 전체에 적용되는 인가 규칙(Authorization Rule)에 일치하도록 보장한다.

이 규칙을 정책(Policy)라고 하며, 관리자만 변경할 수 있고 사용자는 정책을 무시하거나 우회할 수 없으므로, 더 이상 자신의 파일에 모든 사용자가 접근할 수 있도록 설정할 수 없다.



-

보안 강화 리눅스(Security Enhanced Linux, SELinux)는 리눅스 커널에서 강제 접근 제어를 구현한 것으로, 10년 넘게 주류 커널에 통합되어왔다.

안드로이드는 버전이 4.3 (JellyBean MR2) 이 되면서 안드로이드 보안 강화(Security Enhancement for Android, SEAndroid)프로젝트를 통합했다.



-

안드로이드 4.4(Kitkat)에서의 SELinux 는 강제 모드(Enforcing Mode)로 배포되어 시스템 정책을 위반하면 런타임 오류를 발생시킨다.

강화된 정책은 핵심 시스템 데몬에만 적용되고 여전히 앱은 허용 모드(Permissive Mode)로 실행하므로, 정책을 위반하더라도 런타임 오류 없이 로그에만 기록한다.






* 1.2.7. 시스템 업데이트


-

안드로이드 디바이스는 무선(Over-the-Air, OTA) 방식과 PC 에 연결한 후 표준 안드로이드 디버그 브릿지나 이와 비슷한 기능을 가진 벤더 앱을 이용해 업데이트 이미지를 밀어넣는 방식으로 업데이트 할 수 있다.

이 과정에서 시스템 파일 외에도 베이스 밴드(Baseband(모뎀)) 펌웨어, 부트로더(Bootloader) 등 안드로이드에서 직접 접근할 수 없는 부분을 수정해야 하는 경우도 있으므로, 안드로이드를 업데이트할 때는 하드웨어 전체에 접근할 수 있는 최소한의 기능만 제공하는 전용 OS 를 사용한다.

이 OS 를 복구 OS 혹은 간단히 복구라고 한다.



-

OTA 업데이트는 OTA 패키지 파일(ZIP 파일에 코드 서명이 추가된 파일이며, 복구 OS 가 인터프리트하는 작은 스크립트 파일이 담겨 있다.)을 내려받고 디바이스를 “복구 모드(Recovery Mode”)로 재부팅해 수행한다.

아니면 디바이스를 부팅할 때 디바이스 고유의 키 조합을 누름으로써 복구 모드로 들어가 복구 OS 의 메뉴를 이용해 수동으로 업데이트 할 수도 있다.



-

복구 OS 는 업데이트 파일을 갱신하기 전에 이 서명을 추출해 검증한다.

넥서스 디바이스 계열 전체, 개발 전용 디바이스, 일부 제조사 디바이스에서는 디바이스 소유자가 복구 OS 를 교체해 서명 검증 기능을 해제할 수 있다.

서명 검증을 해제하면 서드파티에서 만든 이미지로 업데이트할 수 있다.

복구 및 시스템 이미지를 교체할 수 있는 모드로 디바이스 부트로더를 전환하는 작업을 “부트로더 언락(Bootloader Unlock, 디바이스를 다른 통신사에서 사용할 수 있게 하는 SIM 언락과는 다르다)”라고 한다.



-

대부분 상용 디바이스는 부트로더를 언락하면 제품 보증을 받지 못한다.




* 1.2.8. 검증된 부트


-

모든 검사는 커널이 수행하므로 검증된 부트가 제대로 작동하려면 부팅할 때 커널의 무결성을 검증해야 한다.

이 과정은 디바이스마다 다르지만, 일반적으로 디바이스에 변경 불가능한 하드웨어 고유의 키를 저장해 구현한다.

이 키를 이용해 부트로더와 커널의 무결성을 검증한다.





1.3. 요약


-

안드로이드는 리눅스 커널에 기반을 둔 권한 분리 운영체제다.

상위 수준의 시스템 기능은 바인더라는 IPC 메커니즘을 이용해 통신하는 일련의 시스템 서비스로 구현된다.

안드로이드는 앱을 서로 다른 시스템 아이디(리눅스 UID)로 실행함으로써 서로를 격리시킨다.

기본적으로 앱은 상당히 적은 권한만 갖고 있으며 시스템 서비스, 하드웨어 디바이스, 다른 앱에 접근하려면 권한을 상세하게 요청해야 한다.

권한은 각 앱의 매니페스트 파일에 정의되며, 설치할 때 권한을 부여받는다.

시스템은 앱을 실행할 때 앱의 UID 로 그 앱에 부여된 권한을 알아내고 적용한다.

SELinux 의 장점을 이용해 시스템 프로세스를 격리하는 최신 버전에서는 각 프로세스에 부여한 권한을 더욱 엄격히 통제할 수 있게 되었다.





정리 목차


1. 안드로이드 보안 모델

     1.1. 안드로이드의 아키텍처

          1.1.1. 리눅스 커널

          1.1.2. 네이티브 사용자 공간

          1.1.3. 달빅 가상 머신

          1.1.4. 자바 런타임 라이브러리

          1.1.5. 시스템 서비스

          1.1.6. 프로세스 간 통신

          1.1.7. 바인더

          1.1.8. 안드로이드 프레임워크 라이브러리

          1.1.9. 앱


     1.2. 안드로이드 보안 모델

          1.2.1. 앱 샌드박스

          1.2.2. 권한

          1.2.3. IPC

          1.2.4. 코드 서명과 플랫폼 키

          1.2.5. 다중 사용자 지원

          1.2.6. SELinux

          1.2.7. 시스템 업데이트

          1.2.8. 검증된 부트


     1.3. 요약





댓글0