How to Securely Store Access Token and Secret in Android

How to securely store access token and secret in Android?

Store them as shared preferences. Those are by default private, and other apps cannot access them. On a rooted devices, if the user explicitly allows access to some app that is trying to read them, the app might be able to use them, but you cannot protect against that. As for encryption, you have to either require the user to enter the decrypt passphrase every time (thus defeating the purpose of caching credentials), or save the key to a file, and you get the same problem.

There are a few benefits of storing tokens instead of the actual username password:

  • Third party apps don't need to know the password and the user can be sure that they only send it to the original site (Facebook, Twitter, Gmail, etc.)
  • Even if someone steals a token, they don't get to see the password (which the user might be using on other sites too)
  • Tokens generally have a lifetime and expire after a certain time
  • Tokens can be revoked if you suspect they have been compromised

How to save a token secretly in Android

Android Keystore is a preferred way of storing sensitive information, namely token, password, etc.

However, in case you want to simply store it in SharedPrefs, using one of the existing libraries would come in handy.
You can check SecureStorage library and give it a try.

Storing user token in Android

  1. shared prefs are pretty safe, can be accessed only by your app or root user.
  2. not sure about library, but u can use some simple ndk methods to encrypt/decrypt data. it will give you some extra points of security
  3. Its safe if u use explicit intents

P.s. if your app is a bank client, than you should n't folow this answer

How to securely store a hardcoded API key on Android?

YOUR CHALLENGE

The purpose of it is to be able to send that key everytime I call a webservice that I've made, so I'm sure (or almost sure) that the call comes from the original app that I'm making and that will be published on the Play Store, and not from elsewhere.

This is a very hard task to achieve, but not impossible one and here is where one needs to make a deep dive in mobile API security and understand the mechanics behind it.

It's fundamental to have a clear understand between the difference of who is in the API request versus what is making that API request, otherwise any security solution you may devise/use may not have the intended results.

The Difference Between WHO and WHAT is Accessing the API Server

I wrote a series of articles around API and Mobile security, and in the article Why Does Your Mobile App Need An Api Key? you can read in detail the difference between who and what is accessing your API server, but I will extract here the main takes from it:

The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?

The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.

So, you need to think about the who as the user your API server will be able to Authenticate and Authorize access to the data, and you need to think about the what as the software making that request in behalf of the user.

REVERSE ENGINEERING

I also don't want to store my key in my code, also because it could easily be retrieved via reverse engineering.

That's very true, it's more or less easily achieved depending on the method used to hide the API key, as per the ones you mention:

I've also checked the other methods explained here, but they look like the API key could quite easily be retrieved thanks to reverse engineering.

No matter how secure the API key has been stored, be it in the Android Keystore, encrypted, obfuscated, etc, at some point the API key will need to be in plain text to be sent on the API request header, and in this moment it will be vulnerable to be extracted via static reverse engineering, via a MitM attack or via an instrumentation framework

I have wrote the article How to Extract an API key from a Mobile App with Static Binary Analysis to illustrate how easy it can be done:

The range of open source tools available for reverse engineering is huge, and we really can't scratch the surface of this topic in this article, but instead we will focus in using the Mobile Security Framework(MobSF) to demonstrate how to reverse engineer the APK of our mobile app. MobSF is a collection of open source tools that present their results in an attractive dashboard, but the same tools used under the hood within MobSF and elsewhere can be used individually to achieve the same results.

During this article we will use the Android Hide Secrets research repository that is a dummy mobile app with API keys hidden using several different techniques.

I also wrote another article to achieve it during runtime, Steal that Api Key with a Man in the Middle Attack:

In order to help to demonstrate how to steal an API key, I have built and released in Github the Currency Converter Demo app for Android, which uses the same JNI/NDK technique we used in the earlier Android Hide Secrets app to hide the API key.

So, in this article you will learn how to setup and run a MitM attack to intercept https traffic in a mobile device under your control, so that you can steal the API key. Finally, you will see at a high level how MitM attacks can be mitigated.

An instrumentation framework can also be used during runtime to hook into the code that uses the API key in order to extract it. For example with the popular Frida framework:

Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.

So, no matter what it's done to secure the API key, once it's on the API request will be vulnerable to be extracted.

MOBILE API SECURITY

Anything that runs on the client side and needs some secret to access an API can be abused in different ways and you can learn more on this series of articles about Mobile API Security Techniques. This articles will teach you how API Keys, User Access Tokens, HMAC and TLS Pinning can be used to protect the API and how they can be bypassed.

POSSIBLE SOLUTIONS

I recommend you to read this answer I gave to the question How to secure an API REST for mobile app?, especially the sections Hardening and Shielding the Mobile App, Securing the API Server and A Possible Better Solution.

The possible best solution for your problem is known by Mobile App Attestation, that will let your backend know that what is making the request is indeed a genuine and untampered version of your mobile app, as you wish to achieve:

The purpose of it is to be able to send that key everytime I call a webservice that I've made, so I'm sure (or almost sure) that the call comes from the original app that I'm making and that will be published on the Play Store, and not from elsewhere.

Do You Want To Go The Extra Mile?

In any response to a security question I always like to reference the excellent work from the OWASP foundation.

For APIS

OWASP API Security Top 10

The OWASP API Security Project seeks to provide value to software developers and security assessors by underscoring the potential risks in insecure APIs, and illustrating how these risks may be mitigated. In order to facilitate this goal, the OWASP API Security Project will create and maintain a Top 10 API Security Risks document, as well as a documentation portal for best practices when creating or assessing APIs.

For Mobile Apps

OWASP Mobile Security Project - Top 10 risks

The OWASP Mobile Security Project is a centralized resource intended to give developers and security teams the resources they need to build and maintain secure mobile applications. Through the project, our goal is to classify mobile security risks and provide developmental controls to reduce their impact or likelihood of exploitation.

OWASP - Mobile Security Testing Guide:

The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.

Where to store a JWT token?

If you are using REST service and want to store JWT the best way available is SharedPreferences.You should store in PrivateMode for security.

SharedPreference and SharedPreference.Editor is used to store and retrieve JWT. JWT is retrieved after POST request of Username and Password

 private void makeJsonRequest() {    
String json_req = "json_req";
// String url = getContext().getString(R.string.LOGIN_URL);
String url="";
final JSONObject obj=new JSONObject();
try{
obj.put("username",name);
obj.put("password",pass);

}catch (JSONException e)
{
e.printStackTrace();
}

JsonObjectRequest req = new JsonObjectRequest(Request.Method.POST, url, obj,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}

}) {
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<>();
return headers;
}
};
AppController.getInstance().addToRequestQueue(req, json_req);

To retrieve JWT from response and save in shared preference use

SharedPreferences prefs;
SharedPreferences.Editor edit;
prefs=getActivity().getSharedPreferences("myPrefs",Context.MODE_PRIVATE);
edit=prefs.edit();
try {
String saveToken=response.getString("token");
edit.putString("token",saveToken);
Log.i("Login",saveToken);
edit.commit();
}
catch (JSONException e)
{
e.printStackTrace();
}

To get Token from SharedPreference

private void getToken() {
prefs=this.getActivity().getSharedPreferences("myPrefs",Context.MODE_PRIVATE);
String token = prefs.getString("token","");
}

How can I keep an API key secure from malicious attackers decompiling my app as well as detect malicious uses?

Storing an API key in an app is problematic. You can obfuscate it or hide it in a computation, but if the secret is valuable enough, someone will extract it.

You are on a good track thinking about sending your key from a server. That keeps the key out of the app package itself. You must protect that communication, so TLS is a must, and you should go further and pin the connection to avoid man-in-the-middle attacks.

Rather than sending the key itself, I would send a time-limited token signed by your API key. You'll need to send different tokens over time, but the API key is never directly exposed on the app, and you can change the signing key without requiring an app field upgrade. If a token is stolen, at least it is only valid for a limited period of time.

You still need to make sure you don't send tokens to a tampered app or even a bot who has reverse engineered your protocol. You need to authenticate the installed app package/code as well as check for a safe run time environment (not running in a debugger, no frameworks like frida or xposed, etc.). You could add tamper-detection to your app, but since you're already sending tokens to your app, I think it is a better approach to set up a challenge-response protocol which will cryptographically attest the app. That way you and not the app makes the actual authenticity decision.

For additional background on user and app authenticity, check out a 3 part blog post, starting with Mobile API Security Techniques, or if you prefer video, check out A Tour of Mobile API Underprotection. You can also look at approov.io for a commercial implementation of challenge-response attestation and JWT tokens.



Related Topics



Leave a reply



Submit