I am developing an mobile (Android) API that connects to my server and fetch a few data and send it to the mobile (Android) app that use this API.
I want to be sure that, only persons who has been authenticated with my servers can use the API.
I can give them a user name or password to use the API but what if someone else use the user name and password and send same request to my server(Reply attack). How can I avoid this attack on my API?
I have seen that google use an API key on his APIs like direction that is associated with a digest of signing key; but I am not sure how it is working and whether something like that can help me or not?
Actually I want to be sure that the client APPLICATION that is requesting to the server is the same APPLICATION that I myself has been developed it (not a decompiled and recompiled version of my app).Does some one knows some standard way to authenticate the users of API?
so from what you explained i assume you want to ensure that only Applications you want should be able to use server APIs.
there is not any complete way to ensure this but some steps can make a great protection:
1- you must have a complete list of packagenames which are allowed to send you request
2- you must proguard your sdk code (the aar file you said) and take the username password of developers from out of this aar so there would be no need for developers to know about codes inside the aar something like below:
YourSdkMainClass theInstance = YourSdkMainClass.getInstance("username","password");
3- you must get the application packagename and send it along with username and password every time you call any API (making a encrypted string out of three would be great) - or you can choose a mechanism where you generate a hash token out of these three on a specific API that is called at the beginning of the application and use that token for calling other APIs after that (the token must be invalidated after some hours of not using and new token should be generating)
4- at the server side you must check the received packageName and compare it with the packageName (or list of packageNames) allowed for that specific developer. if everything is OK then response to API call (or send back the token)
NOTE: this scenario can be improved sending the signature of APK instead of packageName. using signature key, multiple apps with same packageName wont be able to send request to the server. of course you need to have signature of the APKs of your developers in server side (ask them when you want to give them the user password)
but all these are perfect if you proguard the aar in a good way.
Related
I had created an Android app that requests resources from the server using Rest APIs. Now how can I check on the server side that the request is from the app and its not from the Postman.
For example,
I am using the following endpoint to get data from the server.
https://api.example.com/get-data/{id}
Now, this endpoint is also accessible from a browser. Therefore I want a solution to make the API in-accessible by all other means. ie. It should be only accessible from my android app instead of any browser, Postman or an android app that is not built by me.
In other words, I want my android app to send a special piece of information that helps the server to authenticate the app.
Besides this, I am also concerned about someone to decompile my APK and take out that information to make API requests.
Note By special information I mean a security key or a mechanism to generate that key.
I am looking for something like the "origin" header that is set by the browser by default and no one else can change this header even the developer of the website. Does anything like this exists in android?
You need to implement an API token, that behaves like a password for your API.
A simple way of doing this is using the Bearer Header with the token value to come from the API and every request you send via your app should include this token as a header.
An example is the Slim 3 Token Authentication which does this for Slim 3 Framework APIs. IF you are using laravel API, try https://laravel.com/docs/5.6/passport
I want to develop an Android application in which anonymous users can send requests to my server through HTTPS. I need to make sure that the requests are coming from my app since anyone can craft an HTPP request and send it. This is very critical in my app.
I read about GCM tokens, but I don't know if they can help me in my issue.
Is there a way to authenticate the requests (coming from the app) without hiding secret keys in code (because I read that hiding secrets is a bad practice as de-compilation is very trivial in Android).
Thanks
You can always generate a unique token for your user. And add that token in the header of your request and verify it on your backend.
Your server could generate unique PIN for each user of your app and it is then sent to your app and displayed over the app.
Users, even though anonymous, are supposed to enter the same PIN before sending the response. In turn request could carry this PIN that server can verify that indeed it has come from the same app.
Further you can set timeout for validity of each PIN is valid so that it is not mis-used and always latest PIN generated are used at the end of any session.
One question further to be answered related to point 1: Is how to ensure that this PIN is sent to your app and not to any fake app.
Answer to that will be : For this every app will get unique applicationid when installed on android device. While installation, this applicationid could register with your server in a discreet manner. So this way you ensure that all your API calls are coming from registered app.
I figured out how to solve this issue after following this guide: https://android-developers.googleblog.com/2013/01/verifying-back-end-calls-from-android.html
Basically, You use the GoogleAuthUtil class, available through Google Play services, to retrieve a string called an “ID Token”. You send the token to your back end and your back end can use it to quickly and cheaply verify which app sent it and who was using the app.
When your server receives the token from your Android app, it’s really important that you verify it. This requires two steps:
Verify that it’s really signed by Google.
Verify that it’s really meant for you.
Thanks.
I'm developing an android app and I want to restrict access to my API to my website and mobile application. I'm not interested in having the user login into my app, rather, registering the client.
I've refrenced these resources for this task:
how to make google endpoints inaccessible from the web?
How do I protect my API that was built using Google Cloud Endpoints?
https://cloud.google.com/appengine/docs/java/endpoints/add-authorization-backend
How do I restrict Google App Engine Endpoints API access to only my Android applications?
Here is what I did thus far:
Generated an android and web client api key from the google cloud console. It looks something like this: ALzfShCF_mD_IVlVVVf2783TG9FG8x7u0s-ZFQE (not real key)
Made a constants class, added these to my API declaration for clientIds
clientId{android_key,web_key} && audience{web_key,android_audiance}
Added a User user param to each method
Rebuilt project, deployed.
All of these resources seemed helpful, especially the documentation. However, I didn't notice any difference. I expected to see, after I followed the documentation and redeploy my backend, both my website and app fail to call my endpoint functions. However, they both worked flawlessly.
Would following these posts or documentation prove my case, or is there something else I must do? I also dont want unauthorized access to my API explorer as well!
Any help would be greatly appreciated!
Edit:
I'm using the wrong keys, I was using the API key instead of the CLIENT Id. Once I updated that I saw that my API requests are failing because the user param is null. Now my question is, how can I not pass a non-null user object without getting the user to login?
I tried making a GoogleAccountCredintal and passing it to my ApiBuilder in my Async task, but its always null.
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(context,APIClientKeys.ANDROID_CLIENT_ID);
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), credential) ...
A very wise web developer once said
"Never Trust the Client".
No matter how sophisticated mechanism you come up with to secure your application, all it takes is a Network Inspector (Like one you can find in your web-browser) and a code inspector (which you can also find in your web-browser). Now some might suggest to obtrucify your client (that is mangling code enough that someone can not just see it). However, if someone really wants to de-obtrucify your application. With significant effort they will and once they have successfully reverse engineered your client, they can write their own malicious client to abuse your endpoints.
So what can you realistically do?
Rate limit usage on some endpoint using some rate-limiting technology (like Limitd) by an IP or other parameters and then start blacklisting IPs if they abuse your service this will make it really hard to abuse your apis.
Force users to login.
How about this:
Setup a secret key on your server and your app. Let’s say it’s SECRETKEY123. When making a request to your API, send an extra parameter called auth. In it pass the md5 (or any other, say bcrypt) hash of your parameters and the secret key. (Note: The secret key should not be posted)
So something like auth = md5(param1 + param2 + SECRETKEY123);
Then on your server perform the same hash using the secret key already stored on the server. Compare the two hashes – I.e the one you submitted and the one you generatd on the server. If they match allow access – otherwise restrict access.
I have an app that retrieves data via http from a server. App sends a POST request with some variables to execute the query and retrieve the data in a JSON format.
The problem is I don't find a way to make the data secure into my server (only accessible to users that have MY application installed). If someone gets my app, and decompile it (even ProGuard won't avoid this for too long) a modded app could start sending requests to my server, using exactly the same protocols, parameters and IP address.
So, in a nutshell, the question is: Is there a way to check (server side, of course) if a request is coming from a legit user?, any way to check if the requester is using my app and not a modded one?
PS: I've been looking for questions like this one and only found another close one that suggested a "user login" approach as answer. I don't want to bother my users with any login mechanics.
Thanks in advance.
Google offers a method to verify back-end calls from an Android app as part of Google Play Services which allows you to verify that the back-end call came from your signed application. One advantage that it has is there is no user login required to verify calls due to the client ID scope used to get the auth token.
I have a pre-existing iOS & Android app, that I'm making an update for that includes a RESTful services API and Facebook login for user authentication. The general flow of the app is:
Users "logs in" to my app, via Facebook's SDKs, which return an access token to my app.
App calls a RESTful service, including the Facebook access token as a parameter (using HTTPS and SSL)
Service that is called, sends the received access token (and app secret stored only on my servers) to Facebook to verify who the user is, and performs actions based on that. Facebook is set to require app secret from server-side calls.
My app has gained popularity and has several clones already, and I want to prevent these clones from being able to use my RESTful API (as I am sure that they will try to do when I release the update). Let's assume that the clones are smart, are using the same Facebook access tokens that my app does (if this is possible), and are following a similar pattern & frequency of calling the API that my app does.
Is there anyway to ensure, or nearly ensure, that calls to my services are coming only from my app, and not the clones?
Thanks in advance!
You can do this by including a signature in the request, and verifying it.
App Side:
do something like: signature = md5( md5(url + data) + MY_RANDOM_KEY)
append signature to the data, or url, etc.
send call to REST api (as usual)
Server Side:
extract the signature from the body/url (and remove it from there).
calculate what you think it should be: signature_should_be = md5( md5(url + data) + MY_RANDOM_KEY) [keep in mind you've removed signature from url/data so that you get url/data in its original pre-hash state]
verify that signature and signature_should_be are equal
Doing this, along with SSL, should make your API secure enough.
You could do as Tommy Crush suggests and add a secret inside you application. But if you are up against clever opponents, this probably won't help. The attackers can either decompile your application or try to simply reverse engineer your signature algorithm.
It is important to remember that anything stored within your application should be thought of as already compromised, as an attacker can decompile your app and scour through your code as much as he/she pleases and extract anything he/she wants from it. You cannot rely on anything in your application to be safe inside your app, since an attacker can extract it from your app into their app.
It is important to note that you are using trying to use OAuth for authentication, which is not intended for. It is simply meant for authorization, which is not the same as authentication. Authorization simply gives you access to a resource, but does not tell you who accessed it, which is the problem you are facing. To authenticate your users as your real users (or as close as you can get), you would need to add a login service for your service - something like rolling your own OAuth-server, or similar. Then you can decide who can access the resource, which in this case is your RESTful API :)
If this is more work than it is worth, then Tommy's scheme is a good alternative :)
The de facto solution for authentication on restful APIs like Twitter and Facebook use is the OAuth mechanism.
You can find more details here: http://en.wikipedia.org/wiki/OAuth.
OAuth is supported from the majority of the languages with external libraries.
On Android for example there is the https://github.com/wuman/android-oauth-client library.