So, I've been trying to use the Google Play Developer API in our app directly via HTTP requests, and we have a service account that can communicate with the API. Specifically, I'm going to use it for subscription tracking (expiry time, purchase state etc.)
I already have access_token, refresh_token, client_id and client_secret which is encrypted in the app as binary. It is possible to get responses from the API directly, I can tell it works, and I'm fairly sure the method to store the information is secure enough.
Considering this, I was wondering if it is a good idea to use the developer API directly on devices because I don't have a backend server that powerful to secure the connection in between. Would the sent-received information be considered as sensitive and should be completely protected? Or using HTTPS (as developer API requires) is enough?
I'd also like to know if Google permits the usage of developer API in multiple devices (I'm talking about more than 100k devices) instead of from a secure backend server, or if it is completely forbidden and goes against their policy to use it from multiple devices, and that the API has to be used from a backend server directly.
Does anybody use the developer API HTTP calls directly in devices? If you do, can you tell me if you have experienced problems regarding to security or policy? Or, do you know that using it is already forbidden?
Any help is appreciated, thank you.
Side note: I am aware that using a secure backend server is a better option for this occasion, but I'm asking this because I can't use it. Please keep that in mind before answering & commenting on this question, thank you.
The short answer is yes - you can use it directly from the device and nothing will prevent it from even get published on a playstore - I have done it for push notifications and it works.
I know that there is a limitation for some APIs per client_id and there is a limitation of possible client_ids per project(here is a bit more details)
Regarding the access_token, refresh_token, - don't store them in a binary - those values are volatile, thus may and will be changes over time - get them during a runtime of the app and store afterwards.
You may also use Firebase remote config to store sensitive values(or even use Firebase cloud functions to handle API access - it will be much more secure).
access_token, refresh_token, client_id and client_secret - all these values are not considered very private or sensitive generally speaking. The one thing that could be bad - if someone get an access to it - they may use it to access your clients data stored somewhere in you google cloud platform or exceed you APIs limits and make you pay for that.
Thus it is secure depending on the information of your users you want to store and exchange, and which APIs you want to use. No one may tell you if you should or shouldn't do it except you - because no one will share a possible outcome and responsibility, but from a technical point of view there are no significant obstacles for such a thing.
I have a mobile app (Android) that makes tens of thousands of RESTful webservice requests to my server (per day of course).
For a variety of reasons, specifically the fact that my server has limited resources (both in hardware specs as well as in the form of pricey licensed content which is sent to my app via the API responses), I would like to ensure that only my apps are able to make successful API requests to my webservice.
I do know it's at least theoretically possible to do this, at least for Android-based systems because Google has a method to verify backend calls from Android on a trusted 3rd-party server (e.g., your API server). I believe it's based on OAuth and is tied to the requisite Google account that every Android device must have been setup with.
I actually ended up implementing this, but abandoned it after about a month as it needed the GoogleAuthUtil mechanism only provided in the most recent version of Google Play Services which had to be installed on the user's device (and of course this prevented most of my users from upgrading). Another problem is that multiple Google accounts can be on a device, so I'd either have to guess which was the right one, or worse, prompt/annoy the user to choose; these options were absolutely out of the question.
My initial thought on the matter is to use some kind of public key encryption, such as PGP/GPG. Include my API's public key in the app (with the understanding that it's not meant to be secure -- it's a PUBLIC key after all), and then in addition to what I already do to sign my API requests I could encrypt the entire contents using the API's public key.
A few days later (today) I finally got the time to sit down and hash out the design and implementation details, and it quickly dawned on me (as well as Robert below in the comments) that because the API's public key as well as the other signature related logic could theoretically be extracted, a successful hacker could then quite easily generate "genuine" API requests that my API server would decrypt with its private key and be none the wiser.
I did come across these two questions posted on programmers.stackexchange that have some really good answers on the subject by people much smarter than me:
https://softwareengineering.stackexchange.com/questions/219028/how-to-safeguard-a-rest-api-for-only-trusted-mobile-applications
https://softwareengineering.stackexchange.com/questions/220080/is-it-possible-to-check-a-client-side-application-identity-from-server-side
From what I have gathered, I'm willing to say that yes it's theoretically possible (just look at Google's GoogleAuthUtil OAuth-based backend verification system that I linked to above). However, it's incredibly painful to correctly implement/maintain, so unless your API is serving nuclear launch codes it's probably wise just to obfuscate the requests as best you can to prevent 90% of the cheaters.
If a mod wants to remove this question or mark it as a duplicate please feel free. OTOH, if someone comes along wondering the same thing maybe this will help them -- I never thought to ask this on programmers.stackexchange, but most of my leads were found in those questions. And of course in the unlikely scenario that a security guru sees this and can explain how this can be done relatively easily and effectively well that would be great too. ;)
Why not generate on client side public/private keys and use the server public key to send the client private one to the server. Store client private key on server side with some kind of request identifier, and further requests could be crypted with client public key, in order to send user credential (is there any on your server?) for example.
Requests could however come from any kind of client aware of your interface, but at least that requests comes from users with valid credentials, otherwise they would fail (still have to got resources to handle wrong request).
Does this makes sens? I'm really new to this subject, but I also have read tons of articles without coming accross to really well defined solution.
Is there any way to restrict post requests to my REST API only to requests coming from my own mobile app binary? This app will be distributed on Google Play and the Apple App Store so it should be implied that someone will have access to its binary and try to reverse engineer it.
I was thinking something involving the app signatures, since every published app must be signed somehow, but I can't figure out how to do it in a secure way. Maybe a combination of getting the app signature, plus time-based hashes, plus app-generated key pairs and the good old security though obscurity?
I'm looking for something as fail proof as possible. The reason why is because I need to deliver data to the app based on data gathered by the phone sensors, and if people can pose as my own app and send data to my api that wasn't processed by my own algorithms, it defeats its purpose.
I'm open to any effective solution, no matter how complicated. Tin foil hat solutions are greatly appreciated.
Any credentials that are stored in the app can be exposed by the user. In the case of Android, they can completely decompile your app and easily retrieve them.
If the connection to the server does not utilize SSL, they can be easily sniffed off the network.
Seriously, anybody who wants the credentials will get them, so don't worry about concealing them. In essence, you have a public API.
There are some pitfalls and it takes extra time to manage a public API.
Many public APIs still track by IP address and implement tarpits to simply slow down requests from any IP address that seems to be abusing the system. This way, legitimate users from the same IP address can still carry on, albeit slower.
You have to be willing to shut off an IP address or IP address range despite the fact that you may be blocking innocent and upstanding users at the same time as the abusers. If your application is free, it may give you more freedom since there is no expected level of service and no contract, but you may want to guard yourself with a legal agreement.
In general, if your service is popular enough that someone wants to attack it, that's usually a good sign, so don't worry about it too much early on, but do stay ahead of it. You don't want the reason for your app's failure to be because users got tired of waiting on a slow server.
Your other option is to have the users register, so you can block by credentials rather than IP address when you spot abuse.
Yes, It's public
This app will be distributed on Google Play and the Apple App Store so it should be implied that someone will have access to its binary and try to reverse engineer it.
From the moment its on the stores it's public, therefore anything sensitive on the app binary must be considered as potentially compromised.
The Difference Between WHO and WHAT is Accessing the API Server
Before I dive into your problem I would like to first clear a misconception about who and what is accessing an 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.
Think about the who as the user your API server will be able to Authenticate and Authorize access to the data, and think about the what as the software making that request in behalf of the user.
So if you are not using user authentication in the app, then you are left with trying to attest what is doing the request.
Mobile Apps should be as much dumb as possible
The reason why is because I need to deliver data to the app based on data gathered by the phone sensors, and if people can pose as my own app and send data to my api that wasn't processed by my own algorithms, it defeats its purpose.
It sounds to me that you are saying that you have algorithms running on the phone to process data from the device sensors and then send them to the API server. If so then you should reconsider this approach and instead just collect the sensor values and send them to the API server and have it running the algorithm.
As I said anything inside your app binary is public, because as yourself said, it can be reverse engineered:
should be implied that someone will have access to its binary and try to reverse engineer it.
Keeping the algorithms in the backend will allow you to not reveal your business logic, and at same time you may reject requests with sensor readings that do not make sense(if is possible to do). This also brings you the benefit of not having to release a new version of the app each time you tweak the algorithm or fix a bug in it.
Runtime attacks
I was thinking something involving the app signatures, since every published app must be signed somehow, but I can't figure out how to do it in a secure way.
Anything you do at runtime to protect the request you are about to send to your API can be reverse engineered with tools like Frida:
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.
Your Suggested Solutions
Security is all about layers of defense, thus you should add as many as you can afford and required by law(e.g GDPR in Europe), therefore any of your purposed solutions are one more layer the attacker needs to bypass, and depending on is skill-set and time is willing to spent on your mobile app it may prevent them to go any further, but in the end all of them can be bypassed.
Maybe a combination of getting the app signature, plus time-based hashes, plus app-generated key pairs and the good old security though obscurity?
Even when you use key pairs stored in the hardware trusted execution environment, all an attacker needs to do is to use an instrumentation framework to hook in the function of your code that uses the keys in order to extract or manipulate the parameters and return values of the function.
Android Hardware-backed Keystore
The availability of a trusted execution environment in a system on a chip (SoC) offers an opportunity for Android devices to provide hardware-backed, strong security services to the Android OS, to platform services, and even to third-party apps.
While it can be defeated I still recommend you to use it, because not all hackers have the skill set or are willing to spend the time on it, and I would recommend you to read this series of articles about Mobile API Security Techniques to learn about some complementary/similar techniques to the ones you described. 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 Better Solutions
Nowadays I see developers using Android SafetyNet to attest what is doing the request to the API server, but they fail to understand it's not intended to attest that the mobile app is what is doing the request, instead it's intended to attest the integrity of the device, and I go in more detail on my answer to the question Android equivalent of ios devicecheck. So should I use it? Yes you should, because it is one more layer of defense, that in this case tells you that your mobile app is not installed in a rooted device, unless SafetyNet has been bypassed.
Is there any way to restrict post requests to my REST API only to requests coming from my own mobile app binary?
You can allow the API server to have an high degree of confidence that is indeed accepting requests only from your genuine app binary by implementing the Mobile App Attestation concept, and I describe it in more detail on this answer I gave to the question How to secure an API REST for mobile app?, specially the sections Securing the API Server and A Possible Better Solution.
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.
No. You're publishing a service with a public interface and your app will presumably only communicate via this REST API. Anything that your app can send, anyone else can send also. This means that the only way to secure access would be to authenticate in some way, i.e. keep a secret. However, you are also publishing your apps. This means that any secret in your app is essentially being given out also. You can't have it both ways; you can't expect to both give out your secret and keep it secret.
Though this is an old post, I thought I should share the updates from Google in this regard.
You can actually ensure that your Android application is calling the API using the SafetyNet mobile attestation APIs. This adds a little overhead on the network calls and prevents your application from running in a rooted device.
I found nothing similar like SafetyNet for iOS. Hence in my case, I checked the device configuration first in my login API and took different measures for Android and iOS. In case of iOS, I decided to keep a shared secret key between the server and the application. As the iOS applications are a little bit difficult to reversed engineered, I think this extra key checking adds some protection.
Of course, in both cases, you need to communicate over HTTPS.
As the other answers and comments imply, you cant truly restrict API access to only your app but you can take different measures to reduce the attempts. I believe the best solution is to make requests to your API (from native code of course) with a custom header like "App-Version-Key" (this key will be decided at compile time) and make your server check for this key to decide if it should accept or reject. Also when using this method you SHOULD use HTTPS/SSL as this will reduce the risk of people seeing your key by viewing the request on the network.
Regarding Cordova/Phonegap apps, I will be creating a plugin to do the above mentioned method. I will update this comment when its complete.
there is nothing much you can do. cause when you let some one in they can call your APIs. the most you can do is as below:
since you want only and only your application (with a specific package name and signature) calls your APIs, you can get the signature key of your apk pragmatically and send is to sever in every API call and if thats ok you response to the request. (or you can have a token API that your app calls it every beginning of the app and then use that token for other APIs - though token must be invalidated after some hours of not working with)
then you need to proguard your code so no one sees what you are sending and how you encrypt them. if you do a good encrypt decompiling will be so hard to do.
even signature of apk can be mocked in some hard ways but its the best you can do.
Someone have looked at Firebase App Check ?
https://firebase.google.com/docs/app-check
Is there any way to restrict post requests to my REST API only to requests coming from my own mobile app binary?
I'm not sure if there is an absolute solution.
But, you can reduce unwanted requests.
Use an App Check:
The "Firebase App Check" can be used cross-platform (https://firebase.google.com/docs/app-check) - credit to #Xande-Rasta-Moura
iOS: https://developer.apple.com/documentation/devicecheck
Android: https://android-developers.googleblog.com/2013/01/verifying-back-end-calls-from-android.html
Use BasicAuth (for API requests)
Allow a user-agent header for mobile devices only (for API requests)
Use a robots.txt file to reduce bots
User-agent: *
Disallow: /
I have an android application. The application reads data from my server and displays them to the user.
Now, the question is: How to prevent someone from making a bogus app and asking my server to send data to this app?
This wastes both my bandwidth and makes use of my content while allowing people to create competitive apps using my data.
As you know, trying to prevent reverse engineering is like trying to stop piracy: impossible. Android reverse engineering especially it's like stealing candy from a baby.
Use API Tokens. Possible solutions:
HTTP Basic Auth example (only if you are using https)
Query Paramter (like https://example.com/resource?token=3786428762) (also only over https)
HMAC - sophisticated and more complex to implement, requires substainsial redesign of the backend communication, but the most secure
But mind you, either way you need to somehow hardcode a key/salt/hash/password in your app which can be reversed engineered one way or the other. There is no real (practical) possibility in Android to avoid rogue clients from accessing your backend (especially in rooted devices).
I would recommend HTTP Basic Auth since it's the best tradeoff in effort, usability and security (It's also used by the majority of public apis) It's very easy to implement since you only need to send a hardcoded http header, it's supported by practically every http server and it does not change your API and pollute it with query parameter and it's also reasonably secure if used over https.
Make the server require an API key and obfuscate the key in your code, see this answer: Best Practice for storing private API keys in Android
If you use http server, you can use http auth basic
Basic access auth
You could use something like reCAPTCHA to verify that the client is not a bot.
I'm about to start the design of an application for Android (and possibly later on iPhone, if I ever get around learning it). In this application I will need to send and retrieve various information to a backend (that me myself also will need to design and code). The information will most likely be in json format.
How would I go about making this data as safely transmitted as possible? Is https the only anser to this? Or are there any other smart solutions to this?
TLS (including HTTPS), where you validate the certificates from the client and the server is the safest mechanism, and doesn't require you to reinvent authentication in some flawed way.