I have been using AWS (Amazon Web services) and in particular simpleDB for a couple of smartphone apps using their iOS/android client libraries.
So far, the data was very benign so I didn't worry too much about data protection.
My next app project will require a "users" table/domain containing usernames and passwords.
What I'm worried about is that someone reverse-engineer the Android java version of the app, then it will be easy to get all the simpleDB data, including all the passwords.
the basic TVM thing (Token Vending Machine, where a temporary token replaces the AWS credentials which are not in the code) doesn't seem to protect against that scenario so it would be great to hear what people think is the recommended approach to do the login part of the app using AWS without being completely unsafe.
Having the passwords table stored somewhere else/accessed in a different way?
Any comment appreciated, Many Thanks.
I can suggest you two approaches to keep your app protected -
1st Approach :
You can keep your AWS secret key into a file with in your app that will be encrypted using private key. On start-up, your code will read that file using public key and can only get your AWS secret key. Please remember following points in this approach -
Your code must be obfuscated.
Your secret key must be in encrypted form into the file so you will get double protection.
Your file must be digitally signed.
2nd Approach :
You can also create your own web site that will manage your user authentications and if user is successfully authenticated it will send AWS Secret key after encrypted it with private key, in his response to the app and your app will use that AWS Secret key after decrypting it with public key. Please remember following points in this approach -
1. Your response must be returned in encrypted form.
2. You site must be secure and must run on HTTPS.
3. Your code must be obfuscated.
Related
I have read about Parse server which was created by facebook , but I think there are serious security issues.
I can decompile other people apk and get Parse master key, appId and then I can connect this people parse server from my own application and can do whatever I want to do with his data which very dangerous
Even I can make while(true)loop and insert infinite data to the parse server.
So how can I connect any API in Android Studio securily?
You shouldn't put the master key anywhere publicly available. If it's in your APK, you're doing something dangerously wrong. Master key should only be an environment variable on your server.
Sure, you could get anybody's app id and client key (if they added one) by decompiling, but that's the same with basically any API. You need to use the security tools provided by Parse, namely CLPs and ACLs. You shouldn't have any data too sensitive on your server at all. I.e., you never need to store a user's actual payment information, you should use a payment API, pass any information needed to them directly from clients, and store the tokens they give you. I.e. with Stripe, there is a "public key" that is used on the client to talk to their secure server, pass credit card info, and create a card token, and you pass that card token back to your server, which can use the secret key, which should absolutely never be put in a client app, to create charges and things.
CLPs and ACLs restrict access to your objects. CLP (Class Level Permissions) are used to restrict entire tables. They have a cool thing called Pointer Permissions, so if an object has pointers to a user, you can set it to the user set on that field can access their objects. You can restrict public access so you can only get an object with the id, but not find it in a query. You can completely restrict read access, and you should restrict write access on most classes. Business logic goes on the server, you can verify a session token to make sure a user should be accessing an object and then use your master key to actually do necessary updates.
Parse-Server has all of the security implementation you need to protect your user's data. You just have to implement it properly. If you don't use CLPs and ACLs, anyone can decompile your app and get your entire database.
Also, Parse wasn't created by Facebook. It was acquired, then shut down and open sourced about a year or so later.
The Application ID is not a security mechanism and you must not ever use the master key in public applications as it allows you to bypass all of your app’s security mechanisms. It's a big mistake to store master key in the app.
Security must be provided to Parse Server by Class Level Permissions and ACLs (and all connections should be made with HTTPS and SSL).
In my experience, Class Level Permissions should rarely grant Public access (default behavior when creating a Class in Parse Dashboard). I only use Master key for testing purposes and to do some queries/savings in afterSave triggers and cloud functions.
I recommend reading the Parse's Security Guide to understand a bit better how to build a secure Parse API. Here is an important fragment that backups my answer:
The master key, on the other hand, is definitely a security mechanism. Using the master key allows you to bypass all of your app’s security mechanisms, such as class-level permissions and ACLs. Having the master key is like having root access to your app’s servers, and you should guard your master key with the same zeal with which you would guard your production machines’ root password.
You can store your API keys, Secret keys or any other important key information in .C file.
For that you have to use NDK.
You can follow this link for how to use the NDK to secure your file. You can also find GitHub demo app link at the bottom of the page.
Note: If you are using NDK it will increase your APK size.
What is the best place to store API keys, Database encryption keys etc. in the app code so that nobody can get it by decompiling the code ? I used proguard to obfuscate the code but it didn't work on Strings.
There is no way to store them in the app. The app can be decompiled or executed on a modified device which provides more access to the app's memory, or the app can be modified by the attacker to add additional logging of network or storage/database traffic, etc.
For authenticating to servers, your app should probably obtain auth tokens (or similar) by exchanging user-entered credentials for such auth tokens or by obtaining these auth tokens from AccountManager or similar APIs. You could also use SafetyNet Attest API (https://developer.android.com/training/safetynet/index.html) to attest to your servers that it is your app signed with your signing key which is making the request.
For database encryption, the app could generate a random encryption key on-device, either linked to user-entered credentials or stored in Android Keystore, or simply rely on protections offered by Android to apps. It depends on your threat model (i.e., why do you think you need to encrypt databases?)
I know that a public client shouldn't use a client secret because, no matter how much you obfuscate it, it won't be protected from reverse engineering.
But, the people in charge of the service I am authenticating to don't want to/can't change it. So, I need to store the client secret and try to protect it from reverse engineering as much as I can.
So, I thought of encrypting it using at build time using gradle and store it in a file. Then, when I need it at run time I decrypt it. But now I have to solve the problem of how to store the encryption key...
I don't know much about security, so, I don't know if this can be solved, or if Android (min sdk 15) provides any mechanism for this kind of scenarios.
Any idea?
This article suggests these options, from less to more secure:
Store in cleartext
Store encrypted using a symmetric key
Using the Android Keystore
Store encrypted using asymmetric keys
Probably, using a combination of #4 and some way to univocally identify the device would be secure enough
Maybe the best option is to use NDK because it can not be decompiled, like Godfrey Nolan points here
Here is a resource I found useful that helped me to implement it link to the resource
Cheers
As you said, whatever you do, how much you try to hide your key, you can not hide it 100%.
But, if you want to make reverse engineer's work harder;
Firstly obfuscate your client (I guess you already do).
Secondly, do not put your key into the client hard-coded. Receive the key after login or user opened the application. And deliver secret key to the client over SSL. Store the secret as byte array and do not save it into the client. Just store in the memory.
These steps do not guarantee the safety of the secret key, but makes reverse engineer's job really hard.
You can also try Dexguard to obfuscate and encrypt the data. Dexguard is made by the same guy that developed proguard.
#Semih's answer was on the right track. The secret key part is what needs to be expanded upon.
The secret key is between the application and the gateway server not to the underlying services.
The gateway server is responsible for converting that key to something specific for the services.
The secret key is built using the following after the login process is complete
the server generates a key pair specific for the client logging in.
The server's public key is sent for encryption specific for the client logging in
the app will generate a key pair for it's own purposes
the app will send the public key encrypted with the server's public key
the server will validate the public key is signed with their public key.
Any future requests would involve the following
All data being sent from client to the server would be encrypted using JWT the message would be signed by the app's private key and encrypted using the server's public key.
The problem is securing #1 anyone can login and get the process started, so how would you prevent that? The only way I can think of is to do a CAPTCHA check on the login.
The solution pushes the storage of the client secrets to the server rather than on the app itself and protecting it using the app's credentials.
I have a platform for building real-time local apps called Bashoto and I am going to build an Android client.
Bashoto applications have the option of being authenticated which is done via generating a one-time use, expiring JSON Web Token (JWT for short) with the application token and a signature to verify that the token is valid. Each connection will have a unique JWT that is generated by signing the content with a Secret.
In a web environment, this means that the client backend has a copy of the Secret, signs the token and passes it to the client front-end which is then used in a request to the BashotoIO server.
The problem here in the mobile environment, and in this case Android, is that keeping that Secret in the application code itself is a potential attack vector, since someone can inspect the APK to find it.
What is the best way to truly keep the Secret secret in an Android application, while still keeping the Bashoto integration simple and streamlined?
I would like the usage to look something like this
Bashoto bashoto = Bashoto.fromAppKey("my-app-key");
bashoto.locate();
BashotoTopic topic = bashoto.topic("my-topic-name"); //token signing and connection happens here
topic.send("Some message that only gets seen by nearby people");
That depends on how secure you want the key to be. You can obfuscate your code using proguard http://responsiveandroid.com/2014/12/10/android-proguard-tutorial.html . This will still have the string literal in there but will be harder to get through a decompilation but not impossible.
If that's not secure enough then you can't keep it in the APK, you have to keep it on a remote server. Ideally that server would use SSL to keep the traffic private. You could fetch the key if you don't have it and store it securely locally using the android keystore https://developer.android.com/training/articles/keystore.html . This means that a user won't be able to decompile your app and find the key.
If you're worried about SSL sucking then you need to move to SSL pinning which will verify the authenticity of any server. https://developer.android.com/training/articles/security-ssl.html#Pinning
Adding the AWS access key and secret key directly in app code is definitely not a good approach, primarily because the app resides on the users device (unlike server side code), and can be reverse engineered to get the credentials, which can then be misused.
Though I find this information everywhere, but am unable to find a definitive solution to this problem. What are my options? I read about the token vending machine architecture for temporary credentials, but I am not convinced that it is any better. If I can reverse engineer the secret key, then I can reverse engineer the code which requests for temporary credentials. And once I have a set of temporary credentials to access S3, I am as good as if I had the key. I can request the temporary credentials again and again, even if they expire pretty quickly. To summarize, if an app can do something, I can do the same as a malicious user. If anything, the TVM can be a bit better at management (rotating credentials, and changing key in case of breach, etc.). Please note we can put the same access restrictions on the secret key, as we plan to do in case of TVM temporary credentials.
Additionally, if Amazon doesn't want people to use the secret key directly in the App, why don't they block it in their SDK, and enforce TVM or the correct solution. If you will leave a path, people are going to use it. I read several articles like these, and wonder why?: http://blog.rajbala.com/post/81038397871/amazon-is-downloading-apps-from-google-play-and
I am primarily from web background, so my understanding of this may be a bit flawed. Please help me understand if this is better, and whether there is a perfect (or may be good) solution available to this problem.
PS: Is there a rails implementation of TVM?
Embedding S3 keys in App code is very risky. Anyone can easily get that key from your app code (no reverse engineering or high skill set required), even if that is stored encrypted it is still compromised just that someone need to try harder (depending on how do you encrypt).
I hope that you understand the advantages of using temporary credentials to access Amazon (S3 etc) resources (mainly security + some others like no app update etc). I think you are more confused about the process to get the temporary credentials from TVM and how that is safer than embedding keys in code.
Every client using TVM first need to register with the TVM server implementation hosted by you. The communication between App (using TVM client) and TVM server is over SSL.
First the app register with TVM by providing UUID and a secret key. Please note that the secret key is not embedded in App code (which I think is main reason for your confusion) but generated randomly (using SecRandomCopyBytes which generates an array of cryptographically secure random bytes) at the time of registration (and hex encoded).
Once the device is registered successfully with TVM, the client TVM store the generated UDID and secret key in a storage called Keychain in iOS and Shared Preferences in Android. The keychain in iOS is the shared storage provided by iOS to securely (encrypted) store information (mainly keys, password etc).
After registration and UDID/Secret Key storage, App can get the token from TVM by sending the UDID, cryptographic signature, and a timestamp. The cryptographic signature is an HMAC hash generated from the timestamp using the secret key. The TVM can use the UDID to lookup the secret key and uses it to verify the signature. The TVM then responds by sending back temporary credentials, which are encrypted using the secret key (uses AES). The application decrypts the temporary credentials using the key and can then use them to access any AWS services for which the temporary credentials are authorized. Eventually, the expiration time of these temporary credentials will be reached, at which point the application can get the fresh temporary credentials, if required.
I am not sure how signed URLs relate to TVM, because I don't understand the concepts 100% but signed URLs really solved the problem for me. I needed a mechanism that would feed web app and mobile app data without allowing for misuse of the credentials. Putting the key in the code is indeed a very bad idea as it may generate a huge bill for the company.
After 3 days of extensive research, I found a simple and, what seems to be, a reliable and relatively safe solution: signed URLs. The idea is, that a very light-weight back-end can generate a temporary URL that will grant the user access to the specific resource for a limited time. So the idea is simple:
the user asks our back-end with a Rest call that he wants a specific resource
the back-end is already authorized with AWS S3
the back-end generates a temporary URL for the user and sends it in the Rest response
the user uses the URL to fetch the data directly from the AWS
A plug-and-play Python implementation can be found here and with a slight modification that I had to use: here.
Of course one more thing to figure out would be how do we authorize the user before we know that we can grant it the URL but that's another pair of shoes.
You should ideally use Cognito Identity for achieving this along with appropriate policies. It should be used with S3TransferUtility and S3TransferManager in iOS and Android SDKs. That would allow for background uploads and downloads as well. Cognito vends temporary credentials for access to AWS resources and is free. Also, you could federate it using UserPools or providers like Google, Facebook if you want secure access.
Thanks,
Rohan