Loading...
Home
  • Tech Blogs
  • Videos
  • Conferences
    • Droidcon News
    • Upcoming Conferences
    • Become a Partner
    • Past Events
    • Keep Me Informed
    • Diversity Scholarships
  • Community
    • droidcon Team
    • How to Hold a Droidcon
  • Android Careers
Sign In

Global CSS

 

Modern Android Security Development

An Opinionated Ultimate Security Toolbox with Insights

 

 
Erick Sumargo
Senior Android dev @Bukalapak and AAD certified
Published: September 08, 2020
Tweet
Share
 

 

1st (Mistake) Practice

Given the “find out how to en-decrypt data in Android” requirement, what would you do?

Unless you are a security expert or developer with a security career dedication that writing the cryptographic code from scratch is just a trivial task, it’s very common for us to start “Googling”, deep dive in “Stack Overflow” to find security-related implementation answers until we probably find below similar snippet:

 

 

Problem:

So what‘s wrong with the snippet? The encrypt and decrypt APIs look solid and have our work done, don’t they?

Well, there’s absolutely nothing wrong with that argument. The interchangeability between the plain and the cipher is proven goes smoothly. But the such old, common, and unsafe to use of the snippet is the most concerning issue we’re really facing now. That issue factors could be the reason that our thought-have-secured assets might be available or easily accessible to an attacker.

 

2nd (Mistake) Practice

Let’s have a short scenario:

 

Backend engineer: “Keep this JWT token, will you? We need it for some later authorizations.”

Probably us: “No problem (better say hi to SharedPreferences now).”

 

Stored in [internal storage]/data/data/[package_name]/[preference_file_name]

 

Problem:

By having a rooted phone/device, please note that everyone literally could access our app XML preference file, located inside the internal storage. Talking about JWT token, the token is literally composed of algorithm-token header type, payload, and verify signature parts, each concatenated by . . And based on this recommended writing,

 

Hacking JSON Web Tokens (JWTs)

And how attackers forge tokens and log in as someone else.

medium.com

 

You might want to read off what are some potential vulnerabilities, how the attackers can forge, manipulate the token parts, and log in as someone else. The only moral story here we can learn to help to prevent such an issue is to not store the token in raw.

 

FAQ:

“But wait a minute… how are we supposed to act now? We understand if we could encrypt the token before storing it in the preference file or somewhere else should satisfy the issue prevention. But the API we use for the encryption scheme is issued on its own as well at the 1st problem.”

 

Well, if we could have our own set of security arsenal that we can rely on, I personally can state, just go ahead. However, if we have less knowledge of any robust cryptographic algorithm or looking for an official and standardized solution, we may want to refer to the next section.

 

Jetpack Security

Or “JetSec” for short, introduced at last Android Dev Summit 2019 provides us a high-level abstraction to allow encrypting data, file, until shared preferences easily without having to really understand the ins and outs of security.

JetSec features Android KeyStore¹ which is the mastermind of every cryptographic operation and we may assume all data secured is done via it. Of course, every secured data associates with a private key which is a primary material used for any cryptographic op. In JetSec, these private keys called keyset. Android KeyStore stores these keyset materials in a container hardware-backed which makes accessing them very hard and it’s not exportable.

 

Note: JetSec also employs Tink, a cross-platform, open-source library from Google to leverage the MasterKey concept for securing all keysets.

 

Gradle Import

 

 

Now let’s jump into practical data encryption with JetSec.

 

Note: The library requires API 23/Marshmallow at minimum.

I personally wouldn’t mind raising the minSdkVersion bar as a trade-off since some of my projects hold some critical sensitive information.

 

MasterKey
Before leveraging any toolbox from JetSec, the generation of the MasterKeyis a prerequisite. Since the minSdkVersion has been set to 23, we’re allowed to use the default AES-based spec for the key generation:

 

 

Though it’s fine for most use cases, we’re also allowed to customize our own spec to secure some of the sensitive data clusters in advance, in case.

 

 

EncryptedFile & EncryptedSharedPreferences
I wouldn’t write too far all about these tools, while we can find their functionalities and implementation details here². Here are some results of the encrypted content along the generated keyset stored inside files:

 

Image for post

EncryptedFile - “Hello World” in ciphertext

 

Image for post

EncryptedFile - Generated keyset

 

Image for post

EncryptedSharedPreferences - JWT “user_token” in ciphertext

 

Image for post

EncryptedSharedPreferences - Generated keysets

 

Note: It’s quite interesting when we find that we literally don’t need to provide our own custom private key string either in a master key generation or when taking both EncryptedFile and EncryptedSharedPreferences in some actions. Hence, we won’t be concerned with another issue about how to secure the private key per se, declared inside the source code. Thanks to the Android KeyStore.

 

In addition to JetSec, below are other security tools compliment which I equally highly recommend to strengthen the security factors:

 

SealedObject

At some point, we may want to have our serialized objects resided in some untrusted mediums³. JavaX’s SealedObject encapsulates the original object, in serialized format, and encrypts the content to protect its confidentiality.

SealedObject will cover us in order to prevent someone from tampering with our serialized object, but the reconstituted object may be lacking transient fields or other information.

 

 

Let’s break-down:

  • The sealObject API is for encapsulating the original object as the SealedObject contract states. We then finally store the encapsulated Serializable result in a somewhere medium.
  • We decide to retrieve back the serialized object. To verify if the serialization is modified, we testify it via unsealObject API. The API should unwrap back to the original one if the object is proven the same still (of course with the corresponding secret key), else an exception will be thrown.

 

Note: We may consider SignedObject and GuardedObject as part of the compliments.

 

R8

 

“One Shot Two Kills”

 

It isn’t only reducing the APK/AAB size significantly, R8 contributes to a matter of security context as well. Today, cracking the source code along with embedded resources/assets can be done easily with some simple tools, like the dex2jar converter, Java Decompiler (JD) & friends, even the Android Studio (3.6+) facilitates the APK/AAB analyzer.

To reduce risk at a minimum of attackers from stealing, recompiling, until publishing back to the store again but with extra profit elements, such as ads, R8’s obfuscation feature does its best to transform any reverse engineering activity much more difficult starting at a point. We can enable R8 via app-level build.gradle file:

 

 

Now an example, let’s compare the decompiled source code between the one which doesn’t benefit the R8 and the one with R8 enabled:

 

Original source code (Kotlin)

 

Decompiled source code with no R8

 

Though it’s harder to read now, still, the essences of the source code, like the security schemes that we’re using, AES256_GCM_SPEC or AES256_GCM_HKDF_4KB can still be clearly spotted at the respective 31st and 37th lines which is not good enough. Now let’s look over the one with R8 enabled:

 

Decompiled source code with R8 (actually there’s no FileEncryptor.class file)

 

No, I’m not pasting the wrong gist. What we’re seeing is valid and I do not say the code is really getting deleted by the R8 but more like it’s obfuscated and inlined to somewhere entry point classes where the invocation of the instance happens, e.g., MainActivity.

This new decompiled project structure should make any tracing-based process from a given APK/AAB becomes one step harder. Strictly speaking,

 

Image for post

Boromir from LOTR

 

Note: dex2jar and JD-GUI tools are used to generate above decompiled source code.

 

Use Case

Last but not least, this writing also brings some daily use cases (based on experience) to the surface that we might want to put great attention on securing them.

 

Google Cloud API Keys

 

Fake API key

 

If we integrate some google cloud services, then we probably have this secret API key, and no matter what, we will want to protect the key in a VERY secure way, else the billing will just blow up.

There are numerous ways we can store the key, like storing it in a C/C++ file using NDK⁴ in the first place or hosting own service provider to keep it. The rest is optional if we welcome JetSec’s EncryptedSharedPreferences for an easier accessing benefit with some security guarantees. We could also add an extra security layer by taking advantage of the GCP’s key restrictions feature.

 

Image for post

Google Cloud Platform (GCP) key restrictions

 

Lock which platforms can make the requests, fill up the forms, and we can sit relaxed for a moment in case the key leaks.

 

Google Cloud Service Accounts

 

Fake service account

 

This credential is literally an alternative to the previous GCP API keys. As far I can state, certain GCP services, like Translation API, require this credential parameter for some advanced auth ops.

Same rule as previous, we want to store the JSON first to some trusted mediums where we favor one and having the JetSec’s EncryptedFile which is a better candidate for securing this credential type in advance.

 

Firebase’s google-services.json

 

Fake google-services.json

 

FAQ:

“Hold on a sec… Are you saying we could secure the JSON as well? We just follow every instruction as stated (below) and let the system do the rest for the Firebase initialization.“

 

Image for post

Firebase integration steps

 

Well, before I’m about to answer “Yes” o̶r̶ ̶”̶N̶o̶”̶, let me show you what could go wrong afterward by the above integration steps:

 

Image for post

Exposed firebase project information

 

So when someone has the APK and decompiles back, we can see the resources.arsc file exposes every embedded resource including our firebase credential information. Judging by this issue, well, in all respects, I personally wouldn’t recommend by following the “official” documented for the firebase integration.

Instead, we could do some hacks by extracting the JSON fields, variablizing them, then we can initialize the Firebase manually. Here’s how:

  • Don’t remove com.google.gms.google-services plugin that has been set by us in app-level build.gradle. We need it to extract the fields.
  • Run ./gradlew :app:assembleDebug (at least in MacOs) in terminal or via Gradle tab > [project_name] > app > Tasks > other > assembleDebug to extract the fields.
  • Now we can remove the plugin along the classpath "com.google.gms:google-services:$whatever_version" set in project-level build.gradle.
  • The extracted result is mapped to an XML file as shown below:

 

Image for post

Located in: ../app/build/generated/res/google-services/debug/values/values.xml

 

  • Copy them and we can initialize the firebase manually.

 

Note: By owning these constants, now we can store somewhere and secure them with any fitted security tool we have mastered.

 

Closing

Thanks for reaching the potato. Few words left by this great said:

 

“Security is always excessive until it’s not enough.”
- Robbie Sinclair

 

In the security world, I believe, there’s no such single tool, silver bullet solution that automatically puts us in the green zone. Great security can only be achieved with a broad collection of complementary tools, every considered security element is taken into account, that forms a layered defense. A layered defense is the only viable defense.

That’s all about. Hope this helps, thanks.

External links:

  1. https://developer.android.com/training/articles/keystore
  2. https://developer.android.com/topic/security/data
  3. https://www.infoworld.com/article/2076237/signed-and-sealed-objects-deliver-secure-serialized-content.html
  4. https://medium.com/programming-lite/securing-api-keys-in-android-app-using-ndk-native-development-kit-7aaa6c0176be

 

 

 

Tags: Android, Android App Development, Security, Jetpack Security, AndroidDev

 

View original article at: 


 

Originally published: September 07, 2020

Android News
Our Engineering Roadmap
Our Engineering Roadmap

By Mark Ng

We just completed our engineering road map for our Android apps at Australia Post. Each year we get together and try to decide on what we are going to do from an engineering perspective for the next 12 months. Each team gets to decide on what should be done now, what they want to complete by the end of the year and whats on the horizon for next year.

By ProAndroidDev -
Android News
Android Activity Lifecycle considered harmful
Android Activity Lifecycle considered harmful

By Eric Silverberg

The Android activity lifecycle is one of the first architectural concepts learned by a new Android developer. Ask any Android dev and they’ll likely all have seen this handy diagram from Google: 

By ProAndroidDev -
Android News
Our Safe Approach to Android Jetpack Navigation in a Multi-Modular App
Our Safe Approach to Android Jetpack Navigation in a Multi-Modular App

By Alejandro Weichandt

It has been a year since we started working on the Android version of the mobile app at Sync. During that year, we faced more than once that moment when we had to choose which path to follow on an Architectural decision. This story is about Navigation.

By ProAndroidDev -
Android News
Custom KotlinX Serializers
Custom KotlinX Serializers

By Jobin Lawrance

Let’s say we have a third-party class that we are using as a type in one of our data class that we want to be serialized, then we have to write a custom serializable for @Serializable to work.

 

By ProAndroidDev -
droidcon News

Tech Showcases,

Developer Resources &

Partners

/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/home-details/EmployerBrandingHeader
EmployerBrandingHeader
https://jobs.droidcon.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/jobs-droidcon/jobs.droidcon.com
jobs.droidcon.com

Latest Android Jobs

http://www.kotlinweekly.net/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/kotlin-weekly/Kotlin Weekly
Kotlin Weekly

Your weekly dose of Kotlin

https://proandroiddev.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/pad/ProAndroidDev
ProAndroidDev

Android Tech Blogs, Case Studies and Step-by-Step Coding

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
Zalando

Meet one of Berlin's top employers

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
Academy for App Success

Google Play resources tailored for the global droidcon community

Follow us

Team droidcon

Get in touch with us

Write us an Email

 

 

Quicklinks

> Code of Conduct

> Terms and Conditions

> How to hold a conference

> FAQs

> Imprint

Droidcon is a registered trademark of Mobile Seasons GmbH Copyright © 2020. All rights reserved.

powered by Breakpoint One