Reputation: 181
If my flutter app requires a secret string to operate, say an API-key, then what strategy would prevent a malicious party from being able to extract this API-key from the published app?
I found some discussion threads on this subject, but none seem to arrive at an answer.
Use flutter_secure_storage
I don't think that works. I can use this to pass user input to Keychain/Keystore where it will remain forever safe. Unless I personally type the API key into each installation of my app, this can't be used for storing an API-key, without the API-key being in the code/assets.
Store the API key on a back-end server, only pass results to app
Well that just creates the same problem with extra steps. My Vendor API-key is now safe on my back-end server. But whatever 'key' I am using to police data requests from my back-end server, that needs to be in the Flutter code/assets.
Use a Firebase remote config
Firebase says don't do that:
Don't store confidential data in Remote Config parameter keys or parameter values. It is possible to decode any parameter keys or values stored in the Remote Config settings for your project.
So, those are a couple of ways that I think do not work. Is there actually a strategy that does work?
Upvotes: 17
Views: 4744
Reputation: 455
I'm mentioning the solution which i had used earlier in one of the Flutter apps.
Upvotes: 0
Reputation: 363
A scenario for this: You will need a separate server that generates keys. Your API keys are stored on this server. Let's call this server "Key Server (KS)". The client requests the required API keys from KS when the application is first opened. KS encrypts API keys with SHA-256 or a similar algorithm. This encryption results in: Encrypted API key(s), 1 private key, 1 public key. After this stage, the key server sends the encrypted API keys and the public key that it creates uniquely for the client to the client. KS also sends the public key and private key it has created for the client to your main server. The client application sends its encrypted data and public key to your main server. The main server will give approval by comparing it with the public key it has and will deliver the encrypted data to the client application by decrypting it. You can improve this scenario, modify it and add additional layers of security. For example, setting the validity period for the private key and the public key, or associating it with the account of the logged in user.
Upvotes: 0
Reputation: 2714
I created a platform app with a complete backend and the way I implemented the communication between the client (flutter app) and server backend as well as security is the following:
the secure storag package is using:
So my short term jwt is actually stored on the smartphone where you last logged in and wont be the same after short time or when you will change the device or log in in a different place.
Some more informations and personal experience
When I was deep diving into how security will work in a client to backend communication I had so many open questions and It took me really long to understand, that you can't lock your api backend to the outside. Everyone can call big companys apis if you know them just with applications like postman in the exact same way you are testing your backend code. Why im telling you this?
I invested so much time finding solutions to build a solid and secure implementation between client and backend, providing environnment variables, writing more complex code, saving critical information somewhere, put 3rd party services between the client backend communication which holds the critical information and so on. In the moment where you will save any kind of critical api or credential on the client you won't have any control. People than can do whatever they want compiling your app or any other stuff. Keep in mind: Never trust the client
You are on the wrong track If you are trying to hold the final "key/secret" at the client, posting it to your backend which needs to validate it. Forget this approach. I think many people like me at this time, who didnt yet investigate in secure applications will have the exact same thoughts.
Reading the above, the 5 steps I described earlier is a good start to bring solid security into your application. Yes it's much more work and more complex implementing it, but you can confirm, that whatever the client tries to do, the door to your backend is not unlocked by compiling the app reading some keys from your app.
Upvotes: 1
Reputation: 472
Restricting API key to authorised users is not a great security benefit assuming it's easy to register a new one and you are facing all mighty intruder who managed to reverse-engineer your whole code and API key is constant between all users.
Also, I believe, that if somebody has managed to reverse-engineer your whole application it should be possible to do a memory dump of the application at the moment we decrypt (which is unavoidable) our API key in order to use it and steal it.
Best way to theoretically harden intruder's job is to:
I'm not a security engineer and would be happy to see additional info about how difficult is the task of stealing API key in theory for the above case of an Android/iOS Flutter app where we implemented everything beside the last point.
Upvotes: 0
Reputation: 17596
As others have mentioned, you can store your API keys in Cloud Functions and then make all of your HTTP requests from these deployed functions.
You can also restrict usage of these functions by creating them as Callable Functions and then checking if the caller of the function is authenticated with your Firebase project.
Whenever the function is called, check the auth status of the caller by referencing the context parameter.
if(!context.auth){
throw new functions.https.HttpsError('unauthenticated','This function must be called while authenticated');
}
So in summary:
Upvotes: 0
Reputation: 181
Replying to above.
Personally I do not know how effective de-compiling an .apk can be. But there are millions of people out there, and some might be very good at this. Personally I am assuming 'worst case' that someone could get a hold of my flutter code and run it in Android Studio.
If they can do that, not just 'look' at decompiled code, but actually run it, then they can just use print() anywhere to learn secret strings like api keys.
My current Solution: My project involves user accounts. So I am combining 2 ideas from my original post.
Upvotes: 0
Reputation: 1192
I have some solutions for it.
Split your API key into many Strings..store them at random places and combine them while making the call, in a very complex manner..in short, make your code complex to understand.
Store your API key in a document, and retrieve it, when making the API call.
(..I think this is a better way)
Lemme know what you think. :)
Upvotes: 0