안드로이드 앱의 보안은 왜 중요할까?
우리가 안드로이드 앱을 빌드하면 aab파일 혹은 apk파일로 만들어진다. 뭔가 aab나 apk하면 보안이 강할거 같다는 생각이 들지만 이 방식들은 단순히 우리가 짠 코드들을 압축한 것에 불과하다. 따라서 apk의 압축을 풀면 우리가 짠 코드의 내부가 모두 보인다.
우리가 안드로이드 앱을 빌드하면 윈도우 상에는 그림1과 같은 apk파일이 생긴다. 더블 클릭해도 열리지는 않지만 이를 안드로이드 스튜디오에서 보면 내부의 파일이 아래와 같이 모두 보이는 것을 알 수 있다.
만약 이 상태로 앱을 출시한다면 앱의 리버스 엔지니어링이 가능하다는 뜻이며, 누군가 우리의 코드를 베껴 새로운 앱을 낼 수도 있다는 이야기이다.
따라서 우리는 우리 앱의 구조를 파악하지 못하게 할 장치가 필요하다.
안드로이드 앱의 최적화
다음으로 중요한 것은 앱의 최적화이다. 우리가 사용하지 않는 이미지 리소스나, 폰트가 모두 앱에 들어간다면 앱의 크기가 커질 것이다. 사용자의 불필요한 저장공간을 사용하게 만드는 것이고 우리가 테스트용으로 넣어 놓은 리소스 파일들이나 코드들이 위 apk 압축풀기에 의해 외부로 유출될 수도 있다는 것을 뜻한다.
따라서 우리는 앱을 출시하기 전에 모든 불필요한 리소스를 제거하는 작업을 해야한다. 하지만 이 작업을 매번 사람이 하게 된다면 필요한 파일을 지워버리는 등의 휴먼애러가 발생할 확률이 높다.
따라서 우리는 사용하지 않는 코드와 리소스를 지워줄 장치가 필요하다.
R8을 이용한 보안과 최적화
안드로이드에서는 위 두가지 요구 사항을 만족시키는 R8이라는 도구를 제공한다.
- 앱의 구조를 파악하지 못하게 할 장치가 필요
- 사용하지 않는 코드와 리소스를 지워줄 장치가 필요
R8의 역할은 다음과 같다.
- 사용되지 않는 코드 제거 및 최적화
- 사용되지 않는 리소스 제거
- 코드 난독화를 통한 보안 강화
R8은 앱 수준의 build.gradle 파일에 단 몇줄만 추가하면 위의 3가지를 모두 가능하게 해준다. 사용방법을 알아보도록하자.
R8사용하기
R8을 사용하기 위해서는 앱 수준의 build.gradle 파일을 다음과 같이 수정해야 한다.
android {
..
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
..
}
- minifyEnabled를 true로 바꾸면 사용하지 않는 코드들이 제거되고 최적화 되며 코드를 난독화시켜준다.
- shrinkResources를 true로 바꾸면 사용하지 않는 리소스들이 제거된다.
- proguardFiles는 최적화 되면 안되는 파일들을 정의한다. 이는 뒤에서 설명한다.
난독화는 어떻게 진행되는가?
minifyEnabled를 true로 바꿔서 난독화를 진행하면 클래스 명과 함수명들이 모두 a,b,c 등으로 바뀌게 된다. 이로 인해 클래스명이나 함수명을 알 수 없어 모든 코드 구조를 알지 않는 이상 리버스 엔지니어링이 거의 불가능해진다.
거의 일어나지 않지만 아주 가끔 난독화가 진행된 apk의 디버깅을 해야 할 수 있다. 이때 난독화가 진행된 클래스들은 어떻게 알아볼까? Release Build를 하면 output 폴더에 다음과 같은 mapping.txt가 생긴다.
이 mapping 파일은 빌드 시 어떻게 코드를 난독화 했는지를 알려준다.
난독화 방지하기
위에서 난독화 시 모든 클래스 파일과 함수명이 a, b, c 등으로 바뀐다고 했다. 하지만 우리가 리플랙션을 사용하려면 리플랙션을 사용해야 하는 클래스들은 난독화가 되면 안된다.
이러한 난독화 되면 안되는 클래스들은 proguard에 정의해서 난독화 방지가 가능하다. 위의 build.gradle 파일의 proguardFiles에 해당 proguard 파일이 정의된다. 예를 들어 위 build.gradle 파일의 proguard 파일은 아래 디렉토리에서에서 찾을 수 있다.
예를 들어 우리가 data 패키지의 모든 data class들이 리플랙션을 쓴다고 할 때 아래와 같이 proguard-rules.pro에 다음 -keep문을 추가함으로써 패키지에 속한 모든 클래스와 함수들의 난독화를 방지할 수 있다.
-keep class com.simpli.compose.data.* { *;}
추가적으로 개별 클래스는 @Keep Annotation을 달면 난독화 방지가 된다.
@Keep
data class KotlinWorld(val blogName: String)