Skip to content

Security

Beside helping with day-to-day job at developing Android Application. This codebase helps to secure Android app when there's penetration testing is coming. This codebase implement security based on modules implemented to the app.

Obfuscation

1.0.0 · Feature · All Module

It's possible to decompile apk to its' original form to see the code behind it, it's called Reverse Engineering. When using this codebase, it automatically provide you with proguard configuration based on module used. Enable it like this:

build.gradle
buildTypes {
    debug {
        minifyEnabled true
        shrinkResources true
        debuggable true
    }
    release {
        // Set minifyEnabled and shrinkResources to true, and debuggable to false
        minifyEnabled true
        shrinkResources true
        debuggable false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

When building apk with release variant, this codebase will obfuscate code so it's harder to read.

Warning

When adding another library outside of this codebase, check does it need a new proguard rule. If it is, add it to proguard-rules.pro

Result:

When decompiled from APK to source code, it's obfuscated so it's harder to read.

Emulator and Root Detection

1.0.0 · Feature · Utils Module

This codebase can check does the device that run the app is an emulator or rooted device. From Context call securityCheck():

when (context.securityCheck()) {
    EMULATOR -> {
        // (1)
    }
    ROOTED -> {
        // (2)
    }
    SAFE -> {
        // (3)
    }
}

  1. Define action when the device is an emulator
  2. Define action when the device is rooted
  3. Define action when the device is safe

Check for Debugger

1.2.0-experimental · Experimental · Utils Module

Android devices can be connected with Debugger to monitor all operations that's happening with it. To avoid your application running with devices that connected or waiting to be connected to a Debugger, you can call this method:

checkForDebugger { connected ->
    if (connected)
        // Action when Debugger is connected
    else 
        // Action when Debugger is not connected
}

App Installer

1.2.0-experimental · Experimental · Utils Module

With Android ecosystem, application can be installed from anywhere as long as you have the APK file. It is bad practice to install Android application outside of the Play Store, because the application you installed might be contained with harmful code.

To verify does the application installed from trustful installer, call verifyInstaller() from Context:

SomeFragment.kt
fun initAction() {
    if  (context.verifyInstaller())
        // (1)
    else
        // (2)
}
  1. Define action when the application installed from verified provider
  2. Define action when the application not installed from verified provider

As of right now, verified application is:

  • Android Play Store
  • Amazon App Store
  • Huawei App Gallery

SSL Pinning

1.0.0 · Feature · Data Module

This codebase use CertificatePinner from okhttp for SSL Pinning. When declaring it in koin module, add pinner:

LibModule.kt
val libModule = module {
    single {
        createOkHttpClient(
            interceptors = arrayOf(getHeaderInterceptor()),
            authenticator = null,
            pinner = certificate, // (1)
            showDebugLog = get<Context>().isDebuggable
        )
    }
}
  1. Add the CertificatePinner here!

Room Database Encryption

1.0.0 · Feature · Data Module

Using adb, local database can be extracted and valuable data and information can be leaked. This codebase will encrypt database and so it's harder to open. Call buildDatabase method:

val db = buildDatabase<SampleDatabase>( // (1)
    ctx = get(), // (2)
    dbName = "Sample.db", // (3)
    passPhrase = "PasswordForDatabase", // (4)
    fallBackMigration = false, // (5)
    migrations = listOf(migrations1, migrations2) // (6)
)

  1. Define RoomDatabase class inside < and >
  2. Context for current application
  3. Name for the database, please provide a valid name
  4. Passphrase to encrypt the database, this key is used to encrypt your database. Without it, it is near impossible to decrypt your database
  5. If set to true the database will clear all data when there's new version of the database, by default false
  6. List of migrations, to put configuration to update database to newer version, by default null

This method return encrypted database that can't be opened manually.

Tip

For better implementation, please use Dependency Injection and initialize the database using singleton.

Result:

Even if database is exported and opened using SQL Viewer, it needs password to open.

Encrypted SharedPreference

1.0.0 · Feature · Data Module

This codebase will automatically encrypt key and the value of SharedPreference. Always use DevPreferenceManager to handle SharedPreference need.

Result:

When opened, Shared Preference keys and values are encrypted.

Other

This codebase can't implement all security in application. Other thing to be consider to improve app security is masking or obfuscating base url, api key, or other secret key.

Tip

Using NDK is recommended. Read more about it here or see sample module.