안드로이드 앱의 보안성을 향상시키는 방법 중에는 여러가지가 있겠지만, 보통은 아래와 같다.

  • 무결성 검증
  • 루팅 감지
  • 난독화

이번 글은 위 세 가지 사항 중 무결성 검증에 대해 작성해보려 한다.

무결성 검증

앱의 무결성 검증은 정보보호의 3요소 중 한가지 이기도 하다. 누군가에 의해 위/변조된 앱이 동작하는 것을 방지하는 것을 목표로 한다.

안드로이드 앱은 디컴파일 툴을 이용하여 어느정도 디컴파일이 되기 때문에, 누군가에 의해 임의로 디컴파일 후 일부 소스가 조작되어 다시 컴파일될 수 있다. (이를 막을 수 있는 것이 난독화 처리이다.)

임의로 조작된 앱은 나비효과가 되어 시스템 상에서 큰 문제가 될 수 있다. 또한 이러한 앱이 공유되어 널리 사용되게 된다면… (이하 생략…)

무결성은 소스코드 모듈 난독화를 통해 어느정도 방지할 수는 있지만, 완벽하진 않다. 이를 어느정도 방지하기 위해서는 허가된 사용자만이 수정하고, 배포된 앱만을 사용할 수 있도록 하여야 한다.


어떻게 해야 좋을까?

우리는 앱을 배포하기 위해 빌드 시 Signing을 하게 된다. Signing시에 사용되는 키스토어 파일이 갖고 있는 키와, 이 키스토어로 서명된 앱이 가지고 있는 키를 비교하는 나름(…) 간단한 방법으로 무결성을 검증할 수 있다.

같은 서명 키로 Sign한 앱은 서명키에 대한 Hash값이 동일하기 때문에 이를 비교하여 무결성을 검증할 수 있다. 누군가 임의로 수정 후 다시 컴파일 하였다면 키가 달라지기 때문이다.

아래는 앱에서 서명 키에 대한 hash를 가져올 수 있는 소스다.

fun getHash(): String? {
        try {
            lateinit var result: String

            val info = packageManager.getPackageInfo(
                packageName,
                PackageManager.GET_SIGNATURES
            )
            for (signature in info.signatures) {
                Timber.d(signature.toCharsString())
                val md = MessageDigest.getInstance("SHA-256")
                md.update(signature.toByteArray())
                val hash = Base64.encodeToString(md.digest(), Base64.DEFAULT)
                result = hash
            }
            return result
        } catch (e: NoSuchAlgorithmException) {
            e.printStackTrace()
            return null
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
            return null
        }
    }

SHA-256 키를 가져와 Base64로 인코딩한다.

그리고 아래는 Signing에 사용되는 키스토어 파일(jks)의 Hash를 가져오는 커맨드이다.

$ keytool -exportcert -alias <key alias> -keystore <keystore 파일 경로> | openssl sha256 -binary | openssl base64

이제 위 커맨드에서 나온 값을 서버에 저장하여 앱에서 나온 키와 비교하면 된다.

누군가에 의해 위/변조된 앱이라면 hash값이 다르게 나올 것이고 그에 따라 추가 대응하면 된다.

참고

  • https://right-hot.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%ED%82%A4%ED%95%B4%EC%8B%9C-%EC%96%BB%EB%8A%94-%EB%B0%A9%EB%B2%95-debug-keyhash-release-keyhash-googlePlay-keyhash