봄날은 갔다. 이제 그 정신으로 공부하자

내가 만든 앱은 내가 지키자! (시큐어 코딩, 난독화) 1/3 본문

보안

내가 만든 앱은 내가 지키자! (시큐어 코딩, 난독화) 1/3

길재의 그 정신으로 공부하자 2021. 11. 10. 11:11

개요

Android 앱은 APK 즉, Application Package로 구성됩니다.

개발자가 play store에 aab(App Bundle)로 앱을 등록해도 실제 사용자가 다운로드 받는 앱은 apk 형식의 파일 입니다.

apk 파일은 디컴파일을 통해 소스 형태로 되돌릴 수 있습니다.

 

즉, 그렇다는 이야기는 악의적인 사용자가 내가 만든 앱을 다운로드 받아 디컴파일을 통해 앱을 빌드 가능한 상태의 소스로 되돌린 후,

수정해 악의적으로 사용하는 것이 가능합니다.

 

 

안전한 앱을 만드는 방법

이러한 문제점을 해결하기 위해 앱을 만들고 배포할 때 지켜야하는 몇가지 룰이 있으며 해당 룰만 지킨다면 크랙킹으로부터 안전한 앱을 만들 수 있습니다.

 

첫번째는 

크랙커가 디컴파일을 통해 얻은 소스코드에서 유효한 정보를 얻기 힘들도록 난독화 하는 것입니다.

이를 위해 코딩할 때 아래 3가지 사항을 준수해야 합니다.

  - 시큐어 코딩: 빌드된 앱 분석을 어렵게 함.

  - 앱이 저장하는 파일을 난독화: 저장된 파일 탈취를 통한 분석 방지

  - 앱 난독화: 코드를 난독화하여 디컴파일을 통한 앱 분석 방지

 

두번째는

디버깅을 방지하는 방법으로 앱이 적절하지 않은 환경에서 실행되지 못하도록(강제 종료) 하는 것 입니다.

앱이 실행되기 적절하지 않은 환경은 아래와 같습니다.

   - 루팅된 OS에서 실행 되는 경우

   - 디버깅툴이 연결된 경우

   - 개발자 모드가 ON된 경우 (or USB 디버깅 ON)

   - USB Device가 연결된 경우

 

적절하지 않은 환경 체크는 앱이 실행 될때 뿐만이 아니라 앱 실행 중간 중간 수시로 체크를 하여야 합니다.

단, 개발자 모드와 USB Device 연결의 경우, 자신이 만드는 앱의 특성을 파악하여 적절히 판단하여 처리하면 됩니다.

 

시큐어 코딩

시큐어 코딩 관련된 내용은 자세한 설명을 하지는 않고 여기에서는 아래 두가지 부분에 대해서만 설명합니다. 

개발자들이 가장 궁금하게 생각하는건 아래 두가지 일 것 입니다.

   - 소스 코드상에 추가한 주석이 앱에 포함되나요?

   - 앱 디버깅을 위해 Log를 추가하였는데 앱에 포함되나요?

 

소스 코드상에 추가한 주석은 배포 빌드 시 빠지게 되며 앱에 포함되지 않습니다. 

즉, 크랙커가 배포된 앱을 다운로드 받아 디컴파일해도 주석은 보이지 않습니다.

주석은 소스 코드에 추가해도 됩니다.

 

앱 디버깅을 위해 코드 상에 추가한 Log.d(), Log.w(), … 등과 같은 코드는 앱에 포함이 됩니다.

이건 크랙커가 배포된 앱을 다운로드 받아 디컴파일할 필요도 없이 그냥 앱을 마켓에서 다운로드 받아 실행만해도 로그가 줄줄이 보이게 됩니다. 가급적이면 소스 코드에 추가하지 않는게 좋습니다.

 

@_@ 잉! 그럼 개발이 불편해질 것 같은데요?

보안 프로그래밍하다 앱 개발 못하겠어요.!!! ㅠ_ㅠ

라는 분들이 계실텐데 방법이 있으니 걱정하지 않으셔도 됩니다.

자세한 방법은 바로 설명합니다.

 

대부분의 개발자가 릴리즈 빌드에 포함되는 것을 막기 위해 아래와 같이 로그를 출력하는 함수를 재정의하고 DEBUG 모드에서만 로그를 출력할 수 있도록 하고 있습니다.

Object MyLog{
   fun Debug(tag: String, msg: String){
	  if (BuildConfig.DEBUG) {
  	    Log.d(tag, msg)
	  }
   }
   …
}

 

위와 같이 Log.d()가 아닌 MyLog.Debug() 함수를 사용한다면 배포된 앱에서 로그가 출력되는 문제를 막을 수 있습니다.

 

하지만 이 코드는 아직 보안 문제가 남아 있습니다.

위 함수를 호출 할 때 대부분 아래와 같이 호출할 것 입니다.

   MyLog.Debug(“MyLogInAct”, “LoginApi Call”)
   …
   MyLog.Debug(“MyLogInAct”, “LoginApi Result Value: ${result}”)
   …

문자열이 코드에 추가된다는 문제입니다.

이게 왜 문제가 되지?라는 의문이 있을 수 있는데 앱을 아무리 난독화하여도 문자열은 난독화 되지 않기 때문 입니다.

문자열이 난독화되지 않는다는 것은 디커파일 시 이런 문자열이나 “MyLogInAct” 이런 문자열이 “LoginApi Call” 그대로 노출되기 때문에 크래커가 이를 바탕으로 앱을 분석할 수 있는 여지를 주게 됩니다.

그러므로 조금 번거롭더라도 로그는 아래와 같이 사용하는 것이 보안상 안전합니다.

if (BuildConfig.DEBUG)
   Log.d(“MyLogInAct”, “LoginApi Call”)

 

이렇게 코딩하는 경우, if (BuildConfig.DEBUG) 구문으로 인해 아래 Log.d() 함수는 배포 빌드 시 위 코드 두 줄은 빠지게 됩니다.

즉, 이렇게 코딩하는 경우 개발 시에는 로그를 보면서 개발이 가능하며 배포 빌드 시 소스에서 빠지게 되므로 크랙킹에서 안전해지게 됩니다.

 

문자열은 디컴파일에서 그대로 노출되므로 중요한 문자열의 경우 분석이 곤란하도록 별도의 난독화 처리를 하거나 JNI를 사용해 노출이 되지 않도록 처리해야 합니다.

 

문자열을 난독화 했다면 당연히 앱이 사용하는 파일(or DB) 암호화가 필요합니다.

필요에 의해 파일(or DB)를 사용하는 경우가 있는데 개발자가 permission으로 외부 접근 권한을 막았다고 해도 루팅된 OS에서는 접근이 가능하므로 파일(or DB) 저장 시 평문 저장이 아닌 암호화한 후 저장이 반드시 필요합니다.

 

다음으로 난독화에 대해 설명하도록 하겠습니다.

 

난독화

보안 코딩에서 난독화는 두가지(문자열 난독화, 앱 코드 난독화)가 있습니다.

 

문자열 난독화가 필요한 경우는, 

보안성이 낮은 경우, 문자열을 그대로 사용하거나 쪼개고 재조합하는 방식으로 간단히 난독화화면 되지만 보안성의 높은 경우에는 암호화 모듈을 사용해서 암호화 하거나 JNI를 사용하는 방법이 있습니다.

 

* 암호화 모듈에 대해서는 자세한 설명을 하지는 않지만 JNI는 다음글에서 설명합니다.

 

다음은 앱 코드 난독화로 이는 개발자라면 배포 빌드 시 반드시 해야하는 것 입니다.

간혹 앱을 배포하면서 난독화를 안하는 개발자들이 있는데 큰일납니다.

 

반드시 난독화를 하는 것이 좋습니다.

요즘은 난독화 하는 것이 매우 쉽습니다.

 

app의 build.gradle에 아래 코드만 추가해 주면 됩니다.

 

buildTypes {
    release {
        minifyEnabled true 
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
		…
        }
    }
}

 

minifyEnabled 옵션을 “true” 해서 배포 빌드 난독화가 되도록 하였으면 

proguardFiles 옵션에 지정된대로 proguard-rules.pro 파일에 난독화 관련 세부 사항이 정의되어 있습니다.

 

개발 버전에서는 잘 되던게 배포 빌드 시 에러가 나는 경우가 있는데 이게 난독화 때문에 그렇습니다.

간혹 배포가 급한 경우 슬그머니 난독화를 끄고 빌드해 배포하는 경우가 있는데… 그러시면 안됩니다… ㅠ_ㅠ

 

난독화 옵션 관련해서는 아래만 기억하시면 됩니다.

아래 옵션들만 기억하면 난독화는 쉽습니다.

-keep class io.reactivex.** { *; }

 

경로가 io.reactivex. 하위에 존재하는 모든 class를 난독화 하지 마라 입니다.

 

다음으로 사용하지 않는 함수 및 최적화를 하지 마라 입니다.

-dontshrink
-dontoptimize

 

난독화 시 사용하지 않는다고 생각해서 함수를 삭제하는데 이게 잘못된 경우가 있습니다.

위의 -keep class로 안되는 경우, 해당 옵션을 추가하면 대부분 해결됩니다.

옵션 유무에 따라 생성된 apk 사이즈가 많게는 20%정도 차이나므로 무조건 추가하기 보다는 안되는 경우에만 추가하는것이 좋습니다.

-keepattributes Signature
-keepattributes Annotation

signature와 Annotation을 난독화 하지마라 입니다.

 

빌드 중 난독화 관련 warning이 발생하는 경우 아래 코드를 추가해주면 됩니다.

-dontwarn javax.annotation.Nullable

 

정리

이번 글은 “내가 만든 앱은 내가 지키자” 시리즈 첫번째 글로 개발 및 배포 시 주의해야할 사항에 대해 알아보았습니다.

   - 시큐어 코딩: 개발 빌드와 배포 빌드 시 포함되는 코드 다르게 처리하기

   - 난독화: 배포 빌드 시 앱 코드 난독화하기

다음 글에서는 앱이 배포된 크래커에 의해 디버깅 되는 것을 막는 방법에 대해 설명하도록 하겠습니다.

Comments