414

Most app developers will integrate some third party libraries into their apps. If it's to access a service, such as Dropbox or YouTube, or for logging crashes. The number of third party libraries and services is staggering. Most of those libraries and services are integrated by somehow authenticating with the service, most of the time, this happens through an API key. For security purposes, services usually generate a public and private, often also referred to as secret, key. Unfortunately, in order to connect to the services, this private key must be used to authenticate and hence, probably be part of the application. Needless to say, that this faces in immense security problem. Public and private API keys can be extracted from APKs in a matter of minutes and can easily be automated.

Assuming I have something similar to this, how can I protect the secret key:

public class DropboxService  {

    private final static String APP_KEY = "jk433g34hg3";
    private final static String APP_SECRET = "987dwdqwdqw90";
    private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;

    // SOME MORE CODE HERE

}

What is in your opinion the best and most secure way to store the private key? Obfuscation, encryption, what do you think?

Basic Coder
  • 9,053
  • 5
  • 39
  • 71
  • 15
    https://rammic.github.io/2015/07/28/hiding-secrets-in-android-apps/ – Patrick Dorn Jul 30 '15 at 09:45
  • 1
    i had store in image/png and get key through png as BufferReader – Sumit Nov 11 '16 at 11:25
  • I think that this is a valid concern and posted a similar issue on the Firebase Android SDK github page: https://github.com/firebase/firebase-android-sdk/issues/1583. Let's see if this gets handled. – grebulon May 27 '20 at 08:40

14 Answers14

374
  1. As it is, your compiled application contains the key strings, but also the constant names APP_KEY and APP_SECRET. Extracting keys from such self-documenting code is trivial, for instance with the standard Android tool dx.

  2. You can apply ProGuard. It will leave the key strings untouched, but it will remove the constant names. It will also rename classes and methods with short, meaningless names, where ever possible. Extracting the keys then takes some more time, for figuring out which string serves which purpose.

    Note that setting up ProGuard shouldn't be as difficult as you fear. To begin with, you only need to enable ProGuard, as documented in project.properties. If there are any problems with third-party libraries, you may need to suppress some warnings and/or prevent them from being obfuscated, in proguard-project.txt. For instance:

    -dontwarn com.dropbox.**
    -keep class com.dropbox.** { *; }
    

    This is a brute-force approach; you can refine such configuration once the processed application works.

  3. You can obfuscate the strings manually in your code, for instance with a Base64 encoding or preferably with something more complicated; maybe even native code. A hacker will then have to statically reverse-engineer your encoding or dynamically intercept the decoding in the proper place.

  4. You can apply a commercial obfuscator, like ProGuard's specialized sibling DexGuard. It can additionally encrypt/obfuscate the strings and classes for you. Extracting the keys then takes even more time and expertise.

  5. You might be able to run parts of your application on your own server. If you can keep the keys there, they are safe.

In the end, it's an economic trade-off that you have to make: how important are the keys, how much time or software can you afford, how sophisticated are the hackers who are interested in the keys, how much time will they want to spend, how much worth is a delay before the keys are hacked, on what scale will any successful hackers distribute the keys, etc. Small pieces of information like keys are more difficult to protect than entire applications. Intrinsically, nothing on the client-side is unbreakable, but you can certainly raise the bar.

(I am the developer of ProGuard and DexGuard)

Eric Lafortune
  • 43,056
  • 7
  • 106
  • 100
  • Is this a local server being talked about in the fifth point? Wouldn't this need a computer that requires to stay on always? Sorry, I'm a newbie. Can I use something like Parse? –  Jun 05 '15 at 18:25
  • 4
    @EricLafortune does it not make a difference if the private key string is stored in the Java class vs in the String resource XML? – Alan Apr 15 '16 at 16:16
  • 2
    @EricLafortune Is it now possible to use the Android Keystore system to securely store the keys? ( http://developer.android.com/training/articles/keystore.html ) – David Thomas Apr 29 '16 at 06:09
  • 2
    @DavidThomas: Did you tried using keystore. I want to obfuscate a API key written in Java class. Please reply – Sagar Trehan Jul 14 '16 at 05:49
  • @SagarTrehan no, I haven't tried the keystore approach yet. There is a popular utility called "dexguard" that may be of interest to you there. – David Thomas Jul 14 '16 at 07:33
  • 1
    Is Android KeyStore useful for this? (https://developer.android.com/training/articles/keystore.html#UsingAndroidKeyStore) – Weishi Z Aug 22 '16 at 21:28
  • 2
    I don't understand #5. Doesn't it have the same exact problems as the original problem? – pete Jul 10 '17 at 18:06
  • @pete: #5 means that a server you own acts as a go-between in the authentication. The API keys will be stored only on your server and not be included in any code that leaves your control. – Bart van Ingen Schenau Jul 11 '17 at 10:20
  • What about storing the keys in a database (e.g. embedded sqlite) using a strong key derivation algorithm (e.g. bcrypt, argon2, ...)? Wouldn't it act the same as keeping them everywhere else (even on server) as the only way to get them would be to run the code and intercept the decoding in the proper place? – Yann39 Dec 13 '17 at 13:45
  • @Bart van ignen Schenau, I have the same question as Pete. What's to prevent someone from decompiling your app and seeing how function() works. They could then copy the algorithm and communicate with your server to execute bad things. – sudocoder Oct 22 '18 at 18:27
  • @sudocoder: Naturally, your server would validate that the requests come from a authenticated user. – Bart van Ingen Schenau Oct 22 '18 at 19:00
  • 1
    @BartvanIngenSchenau how would i send requests to a server to validate that I am indeed authenticated? I can think of a solution... I'd send a private key credential... but isn't that the original problem we're trying to solve? – sudocoder Oct 25 '18 at 18:34
  • @sudocoder You ask the user for login credentials to authenticate. If your app does not require user/client authentication, then perhaps all you need is employ rate-limiting and DoS defenses at the backend server. – MEE Sep 20 '19 at 16:49
  • We provide a free and open-source Dexguard alternative to deeply hide secret keys in Android. This is a gradle plugin that uses the NDK and XOR operator to prevent from reverse-engineering : https://github.com/klaxit/hidden-secrets-gradle-plugin – Ben-J Nov 09 '20 at 16:28
82

Few ideas, in my opinion only first one gives some guarantee:

  1. Keep your secrets on some server on internet, and when needed just grab them and use. If user is about to use dropbox then nothing stops you from making request to your site and get your secret key.

  2. Put your secrets in jni code, add some variable code to make your libraries bigger and more difficult to decompile. You might also split key string in few parts and keep them in various places.

  3. use obfuscator, also put in code hashed secret and later on unhash it when needed to use.

  4. Put your secret key as last pixels of one of your image in assets. Then when needed read it in your code. Obfuscating your code should help hide code that will read it.

If you want to have a quick look at how easy it is to read you apk code then grab APKAnalyser:

http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/

marcinj
  • 44,446
  • 9
  • 70
  • 91
  • 48
    if user can decompile app though they could likely determine request that was made to your own server and simply execute that to get secret. No silver bullet here but take a few steps and I bet you'll be fine! If your app is super popular though maybe not.. Great ideas! – Matt Wolfe Jan 28 '13 at 21:11
  • 3
    yeah, number 1 gives no guarantee. – marcinj Jan 28 '13 at 21:34
  • 46
    I really like the idea of hiding keys inside images. +1 – Igor Čordaš Jan 30 '14 at 14:24
  • I prefer number 2, take a look at: https://github.com/sanandrea/CSecretKey waiting for some comments/advices – Sanandrea Sep 13 '14 at 00:11
  • 1
    @MarcinJędrzejewski Would you like to explain more(with sample or snipped code preferably) about forth solution? Thank you. – Dr.jacky Apr 16 '16 at 05:53
  • 2
    @Mr.Hyde this is called steganography, its way too complex to give a sample code here, you can find examples on google. I have found one here: http://www.dreamincode.net/forums/topic/27950-steganography/. The idea is great but since apk code can be decompiled it spoils its beauty. – marcinj Apr 21 '16 at 21:46
  • @MarcinJędrzejewski It's interesting, there are too many algorithm for steganography. Do you know any tools that can use on both windows os side, and android? I want to encode message in PC, and just use deciding method inside my android application. – Dr.jacky Apr 29 '16 at 13:51
  • 1
    I really liked number 4. – Mohsen Mirhoseini Oct 20 '16 at 21:40
  • yeah i already had stored in image file and get key through image as BufferReader, not secure but good to go – Sumit Nov 11 '16 at 11:27
  • How does #1 help? The attacker can just query the server for the secret key before querying your main service, so it's just as easy as before to impersonate your app isn't it? – pete Jul 10 '17 at 17:45
  • How does #3 work? How do you "unhash" – pete Jul 10 '17 at 17:49
  • Correct me if i'm wrong, #1 works because you log in and you're granted a session token. Then you make every call through your server with this session token - the server fetches and returns information for you. That means if I want to call dropbox's api i'd have to go through my server first with my granted session token. – sudocoder Sep 30 '19 at 18:58
  • @sudocoder not really, its explained in comments - this idea was about using request to your server to get api key (or any other secret) over https connection. This way you dont keep secret in apk, but as explained in comment, hacker might find out the http request and try to call it. This is where security over obsurity starts,:-) you could pack your secret in the image using some form of steganografy and decode it in native c++ code. Still clever hacker will simply print this key before the dropbox request is formed - after all that obsurity.... – marcinj Oct 01 '19 at 21:53
  • @sudocoder your idea about using own server as a proxy to dropbox seems very nice, api keys will be protected this way - but it might complicate use of dropbox apis. In recent times I found that fight with hackers is difficult, what worked for me was to analyze what hackers have changed in apk to break security and do fixes around those places to protect them. It takes few hours, maybe a day. Release new updated apk quite often and make sure your content will work only with newest (or two last versions..) versions so that pirates will not be able to use old cracked ones. – marcinj Oct 01 '19 at 21:58
48

Another approach is to not have the secret on the device in the first place! See Mobile API Security Techniques (especially part 3).

Using the time honored tradition of indirection, share the secret between your API endpoint and an app authentication service.

When your client wants to make an API call, it asks the app auth service to authenticate it (using strong remote attestation techniques), and it receives a time limited (usually JWT) token signed by the secret.

The token is sent with each API call where the endpoint can verify its signature before acting on the request.

The actual secret is never present on the device; in fact, the app never has any idea if it is valid or not, it juts requests authentication and passes on the resulting token. As a nice benefit from indirection, if you ever want to change the secret, you can do so without requiring users to update their installed apps.

So if you want to protect your secret, not having it in your app in the first place is a pretty good way to go.

shareef
  • 7,886
  • 12
  • 53
  • 80
Skip Hovsmith
  • 677
  • 5
  • 5
  • 6
    This should be the accepted answer. – ortonomy Jul 28 '18 at 14:42
  • 9
    The problem persists when you want to access the authentication service. It will give you a client id and client secret. Where should we save them? – Ashi Dec 24 '19 at 11:07
  • 2
    doesn't solve private apis where you need to authenticate to your api first in order to use it. where do you get the credentials for all app users? – Kibotu Jan 20 '20 at 15:37
  • @Ashi client id is somewhat obfuscated in a way that only api endpoint knows on how to extract data from obfuscated data like if only some of the characters of client id(where client id is actual client id + some more data to create obfuscated string )only means the actual data but if hacker tries to change or make changes to client id, he doesn't know which data actually represents client id because that is actually known only to api end point on how client id has been obfuscated and how to extract useful data from client id which actually represents client id.... hope u get my point – Simranjeet Singh Oct 25 '20 at 23:48
  • Definitely this must be accepted answer as it's easy to understand and implement – Simranjeet Singh Oct 25 '20 at 23:48
26

Old unsecured way:

Follow 3 simple steps to secure API/Secret key (Old answer)

We can use Gradle to secure the API key or Secret key.

1. gradle.properties (Project properties) : Create variable with key.

GoolgeAPIKey = "Your API/Secret Key"

2. build.gradle (Module: app) : Set variable in build.gradle to access it in activity or fragment. Add below code to buildTypes {}.

buildTypes.each {
    it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}

3. Access it in Activity/Fragment by app's BuildConfig :

BuildConfig.GoogleSecAPIKEY

Update :

The above solution is helpful in the open source project to commit over Git. (Thanks to David Rawson and riyaz-ali for your comment).

As per the Matthew and Pablo Cegarra comments the above way is not secure and Decompiler will allow someone to view the BuildConfig with our secret keys.

Solution :

We can use NDK to Secure API Keys. We can store keys in the native C/C++ class and access them in our Java classes.

Please follow this blog to secure API keys using NDK.

A follow-up on how to store tokens securely in Android

SANAT
  • 6,760
  • 45
  • 58
  • 4
    storing a key in gradle file is secure? – Google Dec 04 '17 at 08:26
  • 4
    @Google `gradle.properties` shouldn't be checked in to Git so this is a way of keeping the secret out of committed source code, at least – David Rawson Dec 09 '17 at 09:40
  • 4
    This doesn't prevent the API key from being bundled into the resulting `apk` (it will be add to the generated `BuildConfig` file), although this is definitely a good idea to manage different API keys (for e.g. in an open source project) – riyaz-ali Mar 08 '18 at 08:07
  • 6
    Using a Java Decompiler will allow someone to view the BuildConfig file and "GoogleSecAPIKEY" – Matthew Mar 13 '18 at 18:57
  • 3
    Your `BuildConfig.java` file will have the key in plain text form. This is no better than what the OP is already doing. – iceman Mar 29 '18 at 12:20
  • 3
    The very large, bold text at the top of your answer should probably not say "secure" if the solution is quite obviously insecure, as pointed out. I know you have an "update" section in there, but many people proooobably don't read that. – mtrewartha Nov 14 '19 at 20:34
  • 1
    About the NDK solution we have created a free gradle plugin that obfuscate and store your key in C++ files, accessible from your Java code. All the details here : https://github.com/klaxit/hidden-secrets-gradle-plugin – Ben-J Nov 19 '20 at 08:53
16

Adding to @Manohar Reddy solution, firebase Database or firebase RemoteConfig (with Null default value) can be used:

  1. Cipher your keys
  2. Store it in firebase database
  3. Get it during App startup or whenever required
  4. decipher keys and use it

What is different in this solution?

  • no credintials for firebase
  • firebase access is protected so only app with signed certificate have privilege to make API calls
  • ciphering/deciphering to prevent middle man interception. However calls already https to firebase
Manohar Reddy
  • 15,894
  • 7
  • 77
  • 109
Ayman Al-Absi
  • 2,278
  • 21
  • 21
  • 1
    with all do respect with this solution we are still the first square. Instead of using credentials , you suggest to use a certificate. Whoever is capable of stealing your credentials is capable of stealing your signed certificate. – Ashi Dec 24 '19 at 11:45
  • 1
    One advantage though, with the suggested solution, we are adding one more complication in front of the hacker. – Ashi Dec 24 '19 at 11:54
15

The App-Secret key should be kept private - but when releasing the app they can be reversed by some guys.

for those guys it will not hide, lock the either the ProGuard the code. It is a refactor and some payed obfuscators are inserting a few bitwise operators to get back the jk433g34hg3 String. You can make 5 -15 min longer the hacking if you work 3 days :)

Best way is to keep it as it is, imho.

Even if you store at server side( your PC ) the key can be hacked and printed out. Maybe this takes the longest? Anyhow it is a matter of few minutes or a few hours in best case.

A normal user will not decompile your code.

  • 1
    Well - not the answer I hoped to get =) ... I thought you can achive great security :( – Basic Coder Jan 28 '13 at 20:57
  • sorry it is not as you wanted a brillinant, ultra safe solution, but for those who can use the compiler, decompiler there is no safe java code: even the native code can be viewed with hexa viewer and decrtyped. At least worth a try... –  Jan 28 '13 at 20:58
  • 1
    Proguard wont obfuscate the actual key though..? Best thing to do is some simple encript/decript routine, that obfuscate will hide. – IAmGroot Jan 28 '13 at 21:05
  • 3
    it is "visible" the decryption routine, is easy to make the reverse and you have the original string –  Jan 28 '13 at 21:06
15

One possible solution is to encode the data in your app and use decoding at runtime (when you want to use that data). I also recommend to use progaurd to make it hard to read and understand the decompiled source code of your app . for example I put a encoded key in the app and then used a decode method in my app to decode my secret keys at runtime:

// "the real string is: "mypassword" "; 
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
    return Utils.decode(Utils
            .decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}

Decompiled source code of a proguarded app is this:

 public String c()
 {
    return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
  }

At least it's complicated enough for me. this is the way I do when I have no choice but store a value in my application. Of course we all know It's not the best way but it works for me.

/**
 * @param input
 * @return decoded string
 */
public static String decode(String input) {
    // Receiving side
    String text = "";
    try {
        byte[] data = Decoder.decode(input);
        text = new String(data, "UTF-8");
        return text;
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return "Error";
}

Decompiled version:

 public static String a(String paramString)
  {
    try
    {
      str = new String(a.a(paramString), "UTF-8");
      return str;
    }
    catch (UnsupportedEncodingException localUnsupportedEncodingException)
    {
      while (true)
      {
        localUnsupportedEncodingException.printStackTrace();
        String str = "Error";
      }
    }
  }

and you can find so many encryptor classes with a little search in google.

Milad Faridnia
  • 8,038
  • 13
  • 63
  • 69
11

This example has a number of different aspects to it. I will mention a couple of points that I don't think have been explicitly covered elsewhere.

Protecting the secret in transit

The first thing to note is that accessing the dropbox API using their app authentication mechanism requires you to transmit your key and secret. The connection is HTTPS which means that you can't intercept the traffic without knowing the TLS certificate. This is to prevent a person intercepting and reading the packets on their journey from the mobile device to the server. For normal users it is a really good way of ensuring the privacy of their traffic.

What it is not good at, is preventing a malicious person downloading the app and inspecting the traffic. It is really easy to use a man-in-the-middle proxy for all traffic into and out of a mobile device. It would require no disassembly or reverse engineering of code to extract the app key and secret in this case due to the nature of the Dropbox API.

You could do pinning which checks that the TLS certificate you receive from the server is the one you expect. This adds a check to the client and makes it more difficult to intercept the traffic. This would make it harder to inspect the traffic in flight, but the pinning check happens in the client, so it would likely still be possible to disable the pinning test. It does make it harder though.

Protecting the secret at rest

As a first step, using something like proguard will help to make it less obvious where any secrets are held. You could also use the NDK to store the key and secret and send requests directly, which would greatly reduce the number of people with the appropriate skills to extract the information. Further obfuscation can be achieved by not storing the values directly in memory for any length of time, you can encrypt them and decrypt them just before use as suggested by another answer.

More advanced options

If you are now paranoid about putting the secret anywhere in your app, and you have time and money to invest in more comprehensive solutions, then you might consider storing the credentials on your servers (presuming you have any). This would increase the latency of any calls to the API, as it will have to communicate via your server, and might increase the costs of running your service due to increased data throughput.

You then have to decide how best to communicate with your servers to ensure they are protected. This is important to prevent all of the same problems coming up again with your internal API. The best rule of thumb I can give is to not transmit any secret directly because of the man-in-the-middle threat. Instead you can sign the traffic using your secret and verify the integrity of any requests that come to your server. One standard way of doing this is to compute an HMAC of the message keyed on a secret. I work at a company that has a security product that also operates in this field which is why this sort of stuff interests me. In fact, here is a blog article from one of my colleagues that goes over most of this.

How much should I do?

With any security advice like this you need to make a cost/benefit decision about how hard you want to make it for someone to break in. If you are a bank protecting millions of customers your budget is totally different to someone supporting an app in their spare time. It is virtually impossible to prevent someone from breaking your security, but in practice few people need all of the bells and whistles and with some basic precautions you can get a long way.

ThePragmatist
  • 476
  • 4
  • 7
  • 1
    You just copy and pasted this from here: https://hackernoon.com/mobile-api-security-techniques-682a5da4fe10 without acknowledging the source. – ortonomy Jul 28 '18 at 14:42
  • 1
    @ortonomy I agree that he should have quoted the article you linked, but he may have forgot it because both work in same place... – Exadra37 Feb 10 '19 at 00:11
  • 4
    Also Skip's article and the blog post they are based on came out a week after my answer. – ThePragmatist Feb 11 '19 at 06:28
8

The most secure solution is to keep your keys on a server and route all requests needing that key through your server. That way the key never leaves your server, so as long as your server is secure then so is your key. Of course there is a performance cost with this solution.

Bernard Igiri
  • 1,266
  • 2
  • 17
  • 33
  • 36
    The problem is - to reach that server which contains all the secrects i should use another Secret Key - I wonder where i will keep that ? ;) What i am trying to say is - This is also not the best solution (don't think there is an ideal solution here) – Mercury Jan 26 '17 at 13:30
  • That's not true, your server is completely under your control. What it requires is entirely up to you. – Bernard Igiri Jan 27 '17 at 10:24
  • 6
    Can you explain here how client can encrypt the data he wants to send to the server, while the keys are in the server side ? and if your answer will be - The server sends keys to the client - So that must be secured as well! so again no magic solution! can't you see?! – Mercury Feb 02 '17 at 20:42
  • @Mercury lolz, I came here and immediately after seeing the "keep your keys in your private server" I just think the same. You also need to secure the key to your private server or the hacker can just go to your server and grab the key. At the end you have a vicious cycle without solution. It's funny cause I came here to find a simple solution of hiding the API key to _MY server_. And they are suggesting I should make another server for that and then run into the some problems over and over again – Ken Feb 27 '17 at 13:05
  • @Ken your If you want to learn about keeping a server secure this is good place to start: https://www.cyberciti.biz/tips/linux-security.html Regardless, SSH with key authentication and VPN/firewall are the basic ways to access a server remotely without giving out access to the world. The SSH key sits on your personal computer. – Bernard Igiri Mar 02 '17 at 22:18
  • @BernardIgiri, Aren't you missing the whole point of it all? The whole point is to be able to access the server from the mobile application you're building without making it vulnerable because everyone who has the app can retrieve the access keys and tokens by dissambling the app. What have ssh with key authentication and keys been stored on your PC to do with that? – Ken Mar 02 '17 at 22:44
  • @Ken so the issue you are trying to resolve is preventing others from using your server? I only know of one solution, authentication. Users will have to create an account and login to access the server. If you don't want people to have to put in their information, you could have the app automate it. The app could generate a random login token on the phone, send the request to the server with the phone #, and the server can respond with a random pin to the phone. Upon verification of the pin the account is created, and the token is all that is needed from there on. – Bernard Igiri Mar 03 '17 at 23:38
  • 2
    @BernardIgiri and then again we are back to square 1. Let's assume, the phone creates a random login and the server accepts that and sends a pin(This is the so called _private server_ we are talking). Then the person who disassembles your app sees that all it takes to access your _private_ server is just some random login that he can create himself. Tell me what stops him from creating one and accessing your server? In fact what is the difference between your solution and actually storing a login or api key to the main server (whose credentials we wanted to store in our private server) – Ken Mar 04 '17 at 09:15
  • 3
    @ken The random number is authenticated against the phone number and physical access to its text messages. If someone cheats you, you have their information. If that's not good enough force them to create a full user account and password. If that's not good enough get a credit card too. If that's not good enough have them call in. If that's not good enough meet them face to face. How secure/inconvenient do you want to be? – Bernard Igiri Mar 08 '17 at 14:01
  • i believe @Bernardlgiri answer is quite good, as the server will make the api call to only a specific api endpoints and will only allow some calls based on the authentication and also firebase security rules. The response from the API call is what would be sent back and not the API key. Kindly enlighten me if this method exposes exploits. – nelsola Oct 30 '20 at 12:50
7

Whatever you do to secure your secret keys is not going to be a real solution. If developer can decompile the application there is no way to secure the key, hiding the key is just security by obscurity and so is code obfuscation. Problem with securing a secret key is that in order to secure it you have to use another key and that key needs to also be secured. Think of a key hidden in a box that is locked with a key. You place a box inside a room and lock the room. You are left with another key to secure. And that key is still going to be hardcoded inside your application.

So unless the user enters a PIN or a phrase there is no way to hide the key. But to do that you would have to have a scheme for managing PINs happening out of band, which means through a different channel. Certainly not practical for securing keys for services like Google APIs.

user1611728
  • 427
  • 6
  • 12
7

Keep the secret in firebase database and get from it when app starts , It is far better than calling a web service .

Manohar Reddy
  • 15,894
  • 7
  • 77
  • 109
  • 15
    but what about credentials to firebase? – the_joric Mar 28 '18 at 15:14
  • 3
    Unfortunately, Firebase database doesn't work in China. – Konjengbam Apr 23 '18 at 17:31
  • 10
    doesn't make sense, attackers can see you firebase details from decompiled code and get any data from your datababse – user924 May 06 '18 at 10:09
  • 3
    I think this is the best solution as firebase Apps uses SHA1 to allow access to server. Decompiling the code will not help to make call to firebase because hacker new app should use exact app stamp to access firebase. Also, stored key should be ciphered before storing in firebase DB and deciphered once received to avoid middle man interception. – Ayman Al-Absi Sep 12 '18 at 22:09
  • When you get the secret from the firebase database through the network, how does that more secure than getting the same secret from another web service through a secure (https) channel? Can you explain? – Csaba Toth Feb 13 '19 at 08:36
  • @CsabaToth see comment of Ayman Al-Absi . Also I am not saying Firebase Database is 100% attack proof but it is better than calling web service for key . – Manohar Reddy Feb 13 '19 at 08:54
  • good suggestion, but for government sector apps, its not prefered option. – shareef Feb 14 '19 at 04:34
  • but in this way (from Firebase database) , How can I use the key in Manifest ? – Noor Hossain Sep 29 '19 at 16:18
  • @NoorHossain what key are you talking about ? – Manohar Reddy Sep 30 '19 at 04:40
  • I'll +1 this because, keeping keys on different server (from API server) makes total sense. – Ankur Dec 26 '19 at 07:30
  • Firebase database has significant downtime. – Rahul Bansal May 12 '20 at 07:40
5

Ages old post, but still good enough. I think hiding it in an .so library would be great, using NDK and C++ of course. .so files can be viewed in a hex editor, but good luck decompiling that :P

Ahmed Awad
  • 1,581
  • 2
  • 15
  • 20
  • 9
    Users can easily make function calls to the shared library and get whatever is hiding there. No need to decopile it. – david72 Nov 03 '16 at 18:14
  • 5
    According to http://www.androidauthority.com/where-is-the-best-place-to-store-a-password-in-your-android-app-597197/ there is no safe way to do it in android at the moment. – david72 Nov 03 '16 at 19:26
  • 1
    @AhmedAwad Don't understand why this is having 3 upvote. any one could easily decompile the app and see how the ndk entry point are being called :/ – Johny19 Jan 08 '17 at 15:16
  • 1
    This answer is almost one of the best options, but the author should mention that it is very important that you should include a call (inside your NDK library) to see if the checksum matches your APK as otherwise someone can call your NDK library outside of your app – Stoycho Andreev Nov 25 '17 at 23:34
  • @Sniper that would be great, except it has a big problem. How do you know what file is "calling" the native method? If you hard-code the name of the apk to check, great, but what if I make my "hack" apk the same folder as the "good" apk? It will check that the "good" apk has good checksum, and it will allow me to execute that native method. Unless there's a way to know the caller file from JNI/C++ side, then it's pointless as the other options. – SocketByte Jul 01 '18 at 16:26
5

The only true way to keep these private is to keep them on your server, and have the app send whatever it is to the server, and the server interacts with Dropbox. That way you NEVER distribute your private key in any format.

Nick
  • 2,320
  • 1
  • 26
  • 36
  • 13
    But how do you prevent the rest of the world from calling the server? – user2966445 Sep 08 '16 at 01:52
  • If by "the server" you mean your webserver where the credentials are - you can use any method you want. simple authentication with username / password, oauth, active directory, etc. etc. Really depends on your application. – Nick Sep 08 '16 at 14:04
  • Maybe I'm missing something, but doesn't this still require storing credentials within the app? – user2966445 Sep 08 '16 at 21:59
  • No, the dropbox credentials are stored on your application server, the app talks to your application server, which handles any dropbox requests. – Nick Sep 08 '16 at 22:32
  • 3
    Right, but you said the app would authenticate with the server first. Doesn't this mean storing another set of credentials in the app? I understand the server would handle the actual dropbox calls. – user2966445 Sep 09 '16 at 02:22
  • 4
    Well, it could mean that, but it a completely separate authorization. But you don't have to. The usecase I am talking about is that your app user would have a login to your app, say using facebook or twitter. You don't store their credentials in your app, you don't even know them. That authorization process allows them access to your api server, which has the credentials to dropbox, but no app or user has access to them directly. – Nick Sep 09 '16 at 14:00
0

Based on bitter experience, and after consulting with an IDA-Pro expert the best solution is to move a key part of the code into a DLL/SharedObject, then fetch it from a server and load at runtime.

Sensitive data must be encoded as it's very easy to do something like this:

$ strings libsecretlib.so | grep My
  My_S3cr3t_P@$$W0rD
RonTLV
  • 2,010
  • 2
  • 19
  • 31