I m creating an app using firebase. As in our app, there is no sign-in concept(users don't need to sign in to the application). so now I need to secure my firebase.
As the API key is publicly exposed, but we can still restrict that API key to some domain or some IP.
These API keys are auto-created by firebase.
Let's consider a web app, I choose the HTTP address and add my domain. It means that the key is bind to the domains which I have entered in the API and Services - Credentials Section.
In the real-time Firebase security rules.
{
/* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
"rules": {
".write": "auth!=null && auth.uid === 'my uid'"
".read": true
}
}
I just add the security for write but for app users(web, android, or ios) as there is no signing concept I set as true value.
But now the question arrives how can I make my firebase secure so that if any other app or web app using our firebase it should not return data.
It will always throw forbidden or unauthorized err but not data as that unauthorized app or domain I haven't bind in mine keys
For this, I have restricted my API key,
For browser key, authorized domains added
For android key, authorized app(SHA and package added)
For the ios key, bundled ids are added.
But the restriction is not working for the API keys.
Although when I added authentication is read also, then API restriction working perfectly (But this still causing the problem as our app has millions of users, it says "The SMS quota for this project has been exceeded. Exceeded quota for verifying password")
So how should I restrict firebase to listen from our domain and our app only?
I even try sign-in in anonymously but it is not a solution as it creates millions of anonymous users which are not correct. Also, the Anonymous account has a 100 million limit.
Also go through App Check, different providers for different platforms but it also has quota limit so didn't check
Hope I m able to explain the question.
Any suggestions would be really helpful
What you're looking for is Firebase's new App Check feature, which protects your backend resources from abuse. For web apps App Check uses reCAPTCHA v3 to reduce the chances of abuse.
But I'd still recommend that you implement Authentication and security rules too. If you don't want to require that your users enter credentials, you can use Firebase's anonymous authentication to generate a unique UID for them. You can then check for that UID in your security rules, and still ensure that each user/device only accesses the data they're authorized for.
Related
We are building a mobile application and its API server with architecture as in the picture below.
We have WSO2 as the API gateway in front of the Spring Boot API Server. We use WSO2 API Manager to restrict who can call the APIs. Only clients that have registered with our WSO2 and have the correct consumer key and secret can call an API through WSO2, by which the client first call to WSO2's token endpoint to exchange the consumer key and secret with an access token, then call the desired API with the access token in header Authorization: Bearer <access token>
We have a problem that we don't know how to keep the consumer secret since security audits prohibit us to store the secret in mobile app installer package.
There were some questions already asked such as
WSO2 API Manager - How does mobile app connect to API Manager?
WSO2 Api Manager OAuth2 DCR security in public native mobile app
But no answers correctly point to the problem. Most of them was mislead by the complexity of oauth2 flow.
To make the problem specific and clear, please assume that our mobile don't have users to login. The goal of this problem is to allow only trusted mobile application to call the API through WSO2.
Please help suggest if this is possible or not. Or we have no choice but to allow anyone to call the API. Or WSO2' consumer subscribtion feature is not designed to be used directly from mobile app at all?
After doing some research, I found 2 options people usually do.
Separate APIs into 2 groups. First group contains APIs that need to be used without user login, such as API to get initialization data or to get data for landing page of the app. Thease APIs are set as public, allow anyone to call without clientId and secret. The seconds group contains secured APIs that required the token. Mobile app can use Oauth2 PKCE flow to exchange the token with user identity proof.
Obfuscate clientId and secret and keep them in mobile app installer package. The APIs are still be separated into 2 groups as before. But the first group requires client-level token (oauth2 client credential type) and the second group requires user-level token (resource owner password or authorization code type)
I prefer option 2. In my opinion, I think the first option does not really make sense. People choosing this option, maybe, just do it to bypass the security audit check list, to not store the secret in public client, without really concern about security problem. It's like when you cannot trust your kids to keep a key to your house safely, so you decided to remove the lock from the door.
Having every APIs protected and keep the key in the client. Even though some hacker can manage to find the secret, he can only hack APIs of the first group and you can track the clientId he used. You know the expect behavior of the client so it is easy to setup an alarm that detect malicious activities from the client and revoke the token, reset the secret and rollout more complex obfuscation algorithm.
You may want to read OAuth 2.0 for Native Apps [RFC7636] spec. It states:
Public native app clients MUST implement the Proof Key for Code
Exchange (PKCE [RFC7636]) extension to OAuth, and authorization
servers MUST support PKCE for such clients, for the reasons detailed
in Section 8.1.
Check the below answer too.
How to implement Oauth2 without sending client_secret in WSO2 APIM
I'm developing an Android application which consumes a public REST API, in which I have been provided with a developer key. How should I implement the key in my application ?
Will every application in different devices have my same developer key embedded into them? And if so, I only have a limited quota for the developer key, How should I manage it?
Or How to have different unique API keys for each app on different devices so that each application has their own quota and how should I manage it?
For example - Scenario 1(Question 1) - Suppose the Developer quota = 1000 hits, and application runs on 5 different devices then, on accessing and retrieving the info from the API would deplete my developer quota very fast.
Scenario 2(Question 2) - On not using the developer key(quota) , here each application on each devices have their individual quota = 1000 hits. Simply like each device having their own account.
I'm new to REST APIs and thought about the scenarios above but I don't know how to implement and manage them or what is the actual correct solution of Implementing a REST API key in my application?
I have already successfully tested my application on my device using my developer key.
For the quota management, it's the backend logic and it handles user requests so you should follow the backend way in scenario 1. Here is how it should work.
Device Login. On success, the server returns an access token as a response. Store token in device safe place(i.e. SharedPreferences in android).
Send the token in Authorization header of every request to the server, Your server should be guarded by Authorization. Server updates the quota consumed for the day. Here is how the server can manage quota,
‣ Identify user based on the token in Authorization header and update the quota.
‣ If quota exceeds, return some meaningful error to the device.
For scenario 2, make the token User Independent (multiple device logins allowed for the same account). By making the token User Independent and above given flow, you can achieve aspects given in your question. let me know if you have a question.
I suggest using JWT Token. as it's a standard JSON web token and globally used. it has several benefits and availability on major platforms.
You can implement the API key either in headers of the API or in the parameters.
For example if you are using Retrofit the implementing key in headers will look like this :
#Headers({"key: your_key"})
#POST("user/classes")
Call<playlist> addToUserlist(#Body UserParam parm);
Or if you want to implement it in parameters it will look like this :
#POST("user/{key}/classes")
Call<playlist> addToUserlist(#Path("key") String your_key);
First thing first, the question is not regarding how to use the Fingerprint scan API recently introduced in Android M. My question is what kind of a design approach should a developer follow to integrate the API on top of already existing security measures (password based/ federated etc.).
So I have an App in production which has an API which takes a username and password (over HTTPS) and generates an access token for the user. The access token is long lived and used to generate a much short lived Session token. User has to authenticate himself using this API and subsequent access to back-end services is authenticated with the session token generated.
Now with the advent of Fingerprint scan API, how do i handle user authentication. Remember I need to generate the session token at some point.
So What kind of use case design do i follow ?
Should it be like user has to login at least once after app installation with the username/password approach.on successful authentication the username and password is retained in persistence in an encrypted manner which in turn is protected by the Fingerprint authentication (this is like 2 level authentication if you consider it that way).
Any better suggestion from anyone who has come across similar use case in their app ?
Related question - Read somewhere, that the keystore stores the keys out of any specific app process. Is it possible for another app to read a key value if it somehow gets hold of the key alias i have used to save the key on the store ?
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.
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?)