android-templates icon indicating copy to clipboard operation
android-templates copied to clipboard

Avoid defining app credentials via BuildConfig

Open luongvo opened this issue 2 years ago • 15 comments

Issue

Currently, we're having a sample to define BASE_API_URL via BuildConfig. BuildConfig will not be obfuscated by proguard so this way is not safe to go, especially when we have more secrets like API_KEY or API_SECRET. We should provide them through a separate class which will be obfuscated in each flavor folder instead.

Solution

By having 2 environments as default: production and staging, we will need to define 2 new ApiEndpointUrl classes in each flavor.

image

Who Benefits?

Developers

I think this is essential because app credentials management is very important.

What's Next?

  • [ ] Remove BASE_API_URL definition via BuildConfig
  • [ ] Define 2 new ApiEndpointUrl classes in each flavor to provide API endpoint urls.

luongvo avatar Apr 15 '22 03:04 luongvo

@Tuubz added reason to be essential ticket

luongvo avatar Apr 18 '22 10:04 luongvo

@luongvo you might want to have a quick check again, simply read a field from BuildConfig, package an APK and then run jadx to reverse it. It seems like if we are not defining

-keep class com.example.BuildConfig { *; } in proguard file, it will be obfuscated like this:

image

Seems like it works nicely these days with proguard/R8. If so, we should continue to keep this practice.

sleepylee avatar Apr 26 '22 05:04 sleepylee

or maybe it worked with the conversion from gradle.properties -> gradle.app -> BuildConfig -> app

https://medium.com/@abhishekdubey_70837/using-gradle-to-secure-app-keys-in-android-9d2796ca4007

the expected outcome is that the plain string must not be visible, either using the class way or this way 🆗

sleepylee avatar Apr 26 '22 05:04 sleepylee

with the class obfuscation, only the var/function name is obfuscated FYI Screen Shot 2022-04-26 at 13 00 07

sleepylee avatar Apr 26 '22 06:04 sleepylee

@luongvo I have checked by decompiling the APK and the result is the same with @sleepylee . 🙏

  • Here is the apiEndpointUrl from the new approach Screen Shot 2022-04-27 at 15 34 44

  • And this is from BuildConfig Screen Shot 2022-04-27 at 15 31 53

The classes/ method is obfuscated only, not the value 😅

manh-t avatar Apr 27 '22 08:04 manh-t

@manh-t it's public repository so we better not leaking client's detail.

sleepylee avatar Apr 27 '22 08:04 sleepylee

@sleepylee oops, I will censor the image, thanks for reminding 🙇

manh-t avatar Apr 27 '22 08:04 manh-t

I can confirm that both BuildConfig & ApiEndpointUrl only obfuscate the function name and not the value itself 🙏

Screen Shot 2565-04-29 at 11 22 27

However, I do have a preference for ApiEndpointUrl (Ex: Secrets.kt):

  • Cleaner code separation
  • No need to Gradle sync after making an update

@luongvo Any thoughts? In case you agree, would you mind rewriting the description of this issue? 🚀

toby-thanathip avatar Apr 29 '22 04:04 toby-thanathip

@Tuubz did you try the solution I provided above? It seems that I and @manh-t receive a new result here with BuildConfig: both the name + value are obfuscated ⭐

sleepylee avatar Apr 29 '22 04:04 sleepylee

@sleepylee Oh, seems like I misunderstood then

Anyways, I tried the following for CoroutineTemplate:

  1. Enable isMinifyEnabled & isShrinkResources to true for debug build
  2. Move BASE_API_URL in to gradle.properties
  3. Adapt build.gradle.kts so BASE_API_URL is used: buildConfigField("String", "BASE_API_URL", baseApiUrl)
  4. Generate an APK
  5. Run jadx on the APK
  6. Open up the result in a text-editor
  7. Search references for BASE_API_URL

Did I miss something here? 🙇

toby-thanathip avatar Apr 29 '22 04:04 toby-thanathip

@Tuubz that sounds correct and the value URL is supposed to be obfuscated as well with this approach 🤔 Not sure what could be missing from your side, so could you please zip the codebase (remove your build/ part to minimize the size) and post it here for us to investigate?

sleepylee avatar Apr 29 '22 04:04 sleepylee

@sleepylee @manh-t I tried this on CoroutineTemplate could you guys do the same? 🙏

If the value is still obfuscated on your side, then something is definitely missing in the code.

Or perhaps something is wrong with my jadx, when I run it it says: finished with errors, count: 27 🙈

toby-thanathip avatar Apr 29 '22 04:04 toby-thanathip

@sleepylee unfortunately, Toby and I got the same result 💸 Although I didn't keep BuildConfig in proguard, it doesn't obfuscate the BuildConfig's value as the image I provided above. I'm using Worpt project for demonstration 🙏 Not sure if there is any extra config from your side, we'd love to know that 🙏

  • And this is from BuildConfig Screen Shot 2022-04-27 at 15 31 53

manh-t avatar Apr 29 '22 05:04 manh-t

Continue discussion here 👋

Short summary:

  • Values can be obfuscated with https://github.com/MichaelRocks/paranoid
  • BuildConfig + properties is preferred because it doesn't require pushing sensitive data directly into the repository

toby-thanathip avatar Apr 29 '22 07:04 toby-thanathip

@luongvo Our plan is to go with the BuildConfig + properties approach instead, what do you think?

If you agree, I can create a new issue and reject this one

toby-thanathip avatar May 05 '22 05:05 toby-thanathip

This issue is now invalid and should be closed

luongvo avatar Dec 29 '22 06:12 luongvo