My Android app contains OAuth consumer secret for Twitter's API. At the moment it's in .properties file in plain text, so it takes zero effort for someone to look it up in APK.
Should I take steps to obscure it (like, rot13 or stored in obfuscated Java code)? Or should I actually avoid doing any of that, as it would create false sense of security?
How do people usually distribute/store OAuth secret in Android apps?
How common it is for the secret to be stolen and abused?
The real question is what does an attacker get from stealing it...
You should do your best to protect secrets but at the end, a highly motivated hacker can always get to it in an installed app. So it's the value of the secret vs. difficulty of extraction.
The value of the client secret is impersonating the application. It doesn't give any access to user data. However, since Twitter supports automatic issuance of credentials to previously approved apps (their sign-in with Twitter flow), an attacker can potentially build a web app with your secret and steal user data using a blind redirect.
The problem with Twitter's implementation is that they do not ask the developer about the nature of the application. If they did, they would not have issued you a secret to begin with, and would block anyone building a web application using your client credentials and stealing data from users who already approved it.
Obfuscating is one option, but a weak one. Moving the secret to a web server acting as an API proxy is another, but that just moves the problem elsewhere because now your app has to authenticate against the proxy server. However, this pattern can be reasonably secure if you require users to log into your site (which can use, via web views, Twitter to log in). This way, someone trying to abuse your proxy will need their users to open accounts on your service, which isn't very appealing.
In short, go ahead and obfuscate it. It doesn't hurt. Consider using the proxy pattern too. And maybe let Twitter know their security policies are "not great".
I would definitely read this analysis by one of the OAuth authors, Eran Hammer-Lahav, which cites another article dissecting Twitter's OAuth secret problems.
My advice would be to obfuscate the key so that it cannot trivially be extracted and you should be safe from chancers and spammers.
Hammer-Lahav's opinion is that OAuth secrets should not be revoked and should merely be used for gathering statistics. Hopefully Twitter are following this advice.
To hide your OAuth secret keys in your Android app you can use the gradle plugin we have developed. It is a free open source alternative to Dexguard. Our hidden-secrets-gradle-plugin uses the NDK and XOR operator to obfuscate keys to prevent reverse engineering.
You can optionally provide a custom encoding/decoding algorithm to improve the security of your key.
Access to the plugin and all the details : https://github.com/klaxit/hidden-secrets-gradle-plugin
Main point of 0Auth is that you do not store any precious sensitive information on device -
so it is ok to store secret on device (much better that real user credentials). In case your device secrets are stolen, user can always invalidate access without need to change his credentials
Related
I am currently developing an android application that uses an API secret and access tokens to access data over TLS.
Instead of storing the secret locally on the app in plaintext I am considering sending it over TLS from something like Firebase. I would send it encrypted and have a method of decryption that is fairly obfuscated. Then the API secret would be used to make requests to the API.
Are there considerations that should be made to protect the keys? My concern is that a malicious entity could decompile the app and insert their own code to find out our method of hiding the API key.
I'm not sure how someone could figure out the key now. I assume they'd decompile the code and redirect the API secret after it's been decrypted.
Eventually, no matter what, I understand that it could be hacked and someone could discover the API secret. How do I then detect that someone has the API secret? They can't hurt other users unless they have their access tokens, which is a different matter, but are there any well-known ways of detecting attacks? The only effect a malicious entity could have is sending many requests to the API servers pretending to be us which would increase our billing, but this should still be protected against. I could rotate my secret but if they already have a method of finding it, then this doesn't do much for me.
To summarize:
What is considered best practice? Should the API secret stay in our servers where we'd make requests from Firebase Functions? How does one detect an attack, or does this depend from API to API? If an attack is detected do I have to force users to update to a new version to make requests and hide the data in a new way in the new version?
I've put a lot of thought into this, but I still have questions I haven't found answers to myself or online. Thank you.
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.
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
I am going to create a Social media Application similar to facebook for both Android and IOS.I have login form where user need to give their uname and password.My server Team is handling webservices.
how to protect uname and password in Android and IOS App.
how to protect uname and pwd on remote ie while transferring from mobile to webservice.(I have an idea of using AES encryption Algorithm)
how to keep webservice url safe inside app(both android and ios)
what are the flaws could happen while creating these kind of app and how to restrict our app from Hackers?
what are the security steps server Team need to implement (they gonna write server in php).
thanks in advance?
Keep the password in the keychain (iOS).
Use SSL to communicate with the server, use POST for the username/password, Pin the certificate.
The webservice URL is public, anyone with a network sniffer will be able to see it.
The major hack will be against the server. Jailbreaking can compromise the app. The keychain is rather immune to jailbreaking.
The main thing for the server is how they handle the user personal information and password. Do not save the password, just a well salted SHA hash of it.
Define the value of the data you are securing from several perspectives: The user's perspective, the value to you,, your reputation, the value to an attacker. Then design the security to the highest level of all perspectives. Keep in mind that high security can be painful to the user. Find a balance.
If you care about security there is only one answer: Have the security designed and vetted by a security domain expert. I always have my designs and code vetted. Such a domain expert will have several years of full-time security experience in this area and possibly a certification such as CISSP. Anything short of this is just a "nice try".
Security bugs are different than normal code bugs. A normal app can have quite a few bugs that are just annoying but still be usable and even a good app. One security bug and there is no security, one security bug is all the attacker needs.
I have 'secured' the communication between my android application and a tls server providing a financial transaction service, currently in development.
The security credentials are stored in a BKS keystore included in the Android apk. The password to the keystore is visible in plain text in the application source:
keyStore.load(is, "passwd".toCharArray());
I am concerned that if someone was to reverse engineer the app, they would be able to impersonate another user and compromise the security of the service.
I was wondering whether there is a fault in my implementation, if anyone else has this concern, and what the best method of securing against this possibility is.
Whenever you store security data on the client it can be compromised by reverse engineering. You may try to obscure it in the code but determined hacker will figure it anyway. So the only way to make it more secure is not to have the password openly in the code. May be you can just ask user for some pin code at the start of the application and use it to decrypt the password?
Are credentials stored in your app unique per user, i.e. every user gets it own apk with unique credentials? If you only have one apk with same credentials then this is as good as no security. Even worse, it gives false feeling of security.
You (your employer) should really hire a security expert to design your system from security point of view.
Here's what I'd do:
App comes without security credentials.
Every user is generated security credentials on server.
Every user gets secret activation code which is generated in secure environment and delivered via alternative channel. Preferably via snail mail. Activation codes are time-limited and can be used only one time.
On first use user types into app the activation code which enables a one-time download of credentials over a secure (https) channel.
User provides password to encrypt the credentials while stored on device.
Every time the app is used user must provide this paswword. If app is not used for some time the app must timeout the session and ask for password again when user wants access.
But don't take my word for granted. You still need a security expert if there are financial transactions involved.
I believe that Diffie-Hellman Key Exchange is what I was looking for. I'd rather not have to re-implement my own version of DH using a complicated process which involves the user.
currently programming for a Processing company-
their are a set of rules and regulations for a transaction application -OR- a POS APP(Point Of Sale application)
the rules are listed online as PCI validation, a certain amount of security has to be issued or it will be a law suit from Visa,inc or Many other Company's.
about your Question, it doesn't follow PCI compliance as that is a security issue.
please read the PCI compliance so that their is a complete understanding of Security, its not good to compromise Cardholder Data.
:)
I have 'secured' the communication between my android application and a tls server providing a financial transaction service, currently in development.
The security credentials are stored in a BKS keystore included in the Android apk. The password to the keystore is visible in plain text in the application source:
keyStore.load(is, "passwd".toCharArray());
I am concerned that if someone was to reverse engineer the app, they would be able to impersonate another user and compromise the security of the service.
I was wondering whether there is a fault in my implementation, if anyone else has this concern, and what the best method of securing against this possibility is.
Whenever you store security data on the client it can be compromised by reverse engineering. You may try to obscure it in the code but determined hacker will figure it anyway. So the only way to make it more secure is not to have the password openly in the code. May be you can just ask user for some pin code at the start of the application and use it to decrypt the password?
Are credentials stored in your app unique per user, i.e. every user gets it own apk with unique credentials? If you only have one apk with same credentials then this is as good as no security. Even worse, it gives false feeling of security.
You (your employer) should really hire a security expert to design your system from security point of view.
Here's what I'd do:
App comes without security credentials.
Every user is generated security credentials on server.
Every user gets secret activation code which is generated in secure environment and delivered via alternative channel. Preferably via snail mail. Activation codes are time-limited and can be used only one time.
On first use user types into app the activation code which enables a one-time download of credentials over a secure (https) channel.
User provides password to encrypt the credentials while stored on device.
Every time the app is used user must provide this paswword. If app is not used for some time the app must timeout the session and ask for password again when user wants access.
But don't take my word for granted. You still need a security expert if there are financial transactions involved.
I believe that Diffie-Hellman Key Exchange is what I was looking for. I'd rather not have to re-implement my own version of DH using a complicated process which involves the user.
currently programming for a Processing company-
their are a set of rules and regulations for a transaction application -OR- a POS APP(Point Of Sale application)
the rules are listed online as PCI validation, a certain amount of security has to be issued or it will be a law suit from Visa,inc or Many other Company's.
about your Question, it doesn't follow PCI compliance as that is a security issue.
please read the PCI compliance so that their is a complete understanding of Security, its not good to compromise Cardholder Data.
:)