OWASP 카테고리: MASVS-PLATFORM: 플랫폼 상호작용
개요
Android 권한은 제한된 데이터 또는 작업에 대한 액세스를 요청하기 위해 앱의 매니페스트에 선언된 문자열 식별자이며 Android 프레임워크에서 런타임에 적용됩니다.
Android 권한 수준은 권한과 관련된 잠재적인 위험을 나타냅니다.
- 일반: 위험도가 낮은 권한이며 설치 시 자동으로 부여됩니다.
- 위험: 민감한 사용자 데이터에 대한 액세스를 허용할 수 있는 위험성이 높은 권한으로, 런타임에 명시적인 사용자 승인이 필요합니다.
- 서명: 권한을 선언하는 앱과 동일한 인증서로 서명된 앱에만 부여되며 일반적으로 시스템 앱 또는 동일한 개발자의 앱 간의 상호작용에 사용됩니다.
권한 기반 액세스 제어와 관련된 취약점은 앱의 구성요소 (예: 활동, 수신자, 콘텐츠 제공자 또는 서비스)가 다음 기준을 모두 충족하는 경우 발생합니다.
- 구성요소가
Manifest
의android:permission
와 연결되어 있지 않습니다. - 구성요소가 사용자가 이미 승인한 권한이 있는 민감한 작업을 수행합니다.
- 구성요소를 내보냅니다.
- 구성요소가 수동 (매니페스트 또는 코드 수준) 권한 확인을 실행하지 않습니다.
이 경우 악성 앱이 취약한 구성요소의 권한을 악용하여 취약한 앱의 권한을 악성 앱에 프록시하는 방식으로 민감한 작업을 실행할 수 있습니다.
영향
취약한 구성요소를 내보내면 민감한 리소스에 액세스하거나 민감한 작업을 실행하는 데 사용할 수 있습니다. 이러한 원치 않는 동작의 영향은 취약한 구성요소의 컨텍스트와 권한에 따라 다릅니다.
완화 조치
민감한 작업에 권한 필요
민감한 권한이 있는 구성요소를 내보낼 때는 수신되는 모든 요청에 동일한 권한을 요구합니다. Android 스튜디오 IDE에는 이 취약점을 감지하고 적절한 권한을 요구하도록 권장하는 수신기 및 서비스의 린트 검사가 있습니다.
개발자는 다음 예와 같이 서비스를 구현할 때 Manifest
파일에서 또는 코드 수준에서 선언하여 수신 요청에 권한을 요구할 수 있습니다.
XML
<manifest ...>
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application ...>
<service android:name=".MyExportService"
android:exported="true"
android:permission="android.permission.READ_CONTACTS" />
</application>
</manifest>
Kotlin
class MyExportService : Service() {
private val binder = MyExportBinder()
override fun onBind(intent: Intent): IBinder? {
// Enforce calling app has the required permission
enforceCallingPermission(Manifest.permission.READ_CONTACTS, "Calling app doesn't have READ_CONTACTS permission.")
// Permission is enforced, proceed with export logic
return binder
}
// Inner class for your Binder implementation
private inner class MyExportBinder : Binder() {
// Permission is enforced, proceed with export logic
}
}
자바
public class MyExportService extends Service {
@Override
public IBinder onBind(Intent intent) {
// Enforce calling app has the required permission
enforceCallingPermission(Manifest.permission.READ_CONTACTS, "Calling app doesn't have READ_CONTACTS permission.");
return binder;
}
// Inner class for your Binder implementation
private class MyExportBinder extends Binder {
// Permission is enforced, proceed with export logic
}
}
구성요소를 내보내지 않음
절대적으로 필요한 경우가 아니라면 민감한 리소스에 액세스할 수 있는 구성요소를 내보내지 마세요. Manifest
파일에서 android:exported
를 구성요소의 false
로 설정하면 됩니다. API 수준 31 이상에서는 이 속성이 기본적으로 false
로 설정됩니다.
XML
<activity
android:name=".MyActivity"
android:exported="false"/>
서명 기반 권한 적용하기
개발자가 제어하거나 소유한 두 앱 간에 데이터를 공유할 때는 서명 기반 권한을 사용합니다. 이러한 권한에는 사용자 확인이 필요하지 않으며 대신 데이터에 액세스하는 앱이 동일한 서명 키를 사용하여 서명되었는지 확인합니다. 이 설정은 더 간편하고 안전한 사용자 환경을 제공합니다. 맞춤 권한을 선언하는 경우 해당 보안 가이드라인을 고려하세요.
XML
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<permission android:name="my_custom_permission_name"
android:protectionLevel="signature" />
단일 작업 엔드포인트
관심사 분리 디자인 원칙에 따라 앱을 구현합니다. 각 엔드포인트는 특정 권한으로 소수의 특정 작업만 실행해야 합니다. 또한 이 좋은 설계 관행을 통해 개발자는 각 엔드포인트에 세분화된 권한을 적용할 수 있습니다. 예를 들어 캘린더와 연락처를 모두 제공하는 단일 엔드포인트를 만들지 마세요.
리소스
- Oversecured 블로그의 앱 보호 구성요소에 대한 Android 액세스
- 콘텐츠 제공자 권장사항
- 런타임 (위험한) 권한
- 관심사 분리 디자인 원칙
- Android 권한 문서
- Android broadcast receiver 보안 도움말
- Android 서비스 보안 도움말
- Android 12 (API 31) 내보내기 기본값이 'false'로 설정됨
- 린트 검사: 내보낸 PreferenceActivity를 내보내서는 안 됨
- 린트 검사: 내보낸 수신자에 권한이 필요하지 않음
- 린트 검사: 내보낸 서비스에 권한이 필요하지 않음