I'm trying to implement my own way of resetting user password for my mobile app. I've come to an idea to use cloud functions as I don't want anything other than Firebase working with my app. The problem is I will need to invoke three cloud functions to reset user password. First one will contain only user's email, second will contain code obtained by user from his password reset email and his email to check if code is valid and third one will contain his email and new password to set from cloud function.
The problem arise when I think about ways to pass this information into cloud functions. I know I can use URL parameters or just send it using POST method. But package that I would like to use to communicate with cloud functions doesn't support any other option than passing URL parameters to cloud function. I know I can write my own HTTP request to pass information using post but I'm thinking if there is any problem with sending this information using URL parameters. It's all sent over HTTPS which should guarantee obscurity of this data. I know that it still can be logged on server, and I don't know if Firebase store logs of cloud function requests with full URL parameters part visible. If yes, it would be big security issue with my app.
So, there are my questions:
Is there a security issue with passing sensitive information through
URL parameters?
Should I create my own solution using plain HTTP requests to pass sensitive information using POST?
Does anyone know if Firebase stores logs with visible URL parameters?
Is this even good idea to use cloud function for this matter? Maybe I should handle it differently?
Just to answer this question for future people like me:
like Renaud Tarnec said in his comment. SSL certificate by default ciphers all URL parameters. So it's safe to pass information this way. Firebase DOES NOT store logs with visible URL parameters when you call cloud functions. It only stores an ID of called function in your logs, so it's not a security threat.
Related
I want to add "Sign-in with Google" as an alternative to creating an account when signing up for our services.
I want the process to retrieve the user's email address and name. That's it.
And this example was all I needed
https://developers.google.com/identity/sign-in/web
Worked great. Very similar to Log in with Facebook, which I added last week.
But now I read that it won't be supported after March 2023.
Using the destined-for-the-dustbin JS code, I can get back useful info about the account I'm logging in with.
ID: 10855600*******690837;Frank;Hart;frank.hart*****#gmail.com
The parameter passed to the callback function has a getBasicProfile() method which does the job
var profile = googleUser.getBasicProfile();
But using the new code, I found (by trial and error) that the parameter passed to the callback function is an object, which has three fields, the only potentially useful one called credential, with content such as:
eyJhbGciOiJSUzI1NiIsImtpZCI6IjQ2Mjk0OTE3NGYxZWVkZjRmOWY5NDM0ODc3YmU0ODNiMzI0MTQwZjUiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2Mjg4NTQzOTcsImF1ZCI6IjY1MjE0Nzk1NjY0My05aWVmdHN2bmZraDVma2x1NHUxOGg1Ymc3MDA0YjdsOC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwODU1NjAwNDY3OTg0NzY5MDgzNyIsImVtYWlsIjoiZnJhbmsuaGFydDA0N0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiNjUyMTQ3OTU2NjQzLTlpZWZ0c3ZuZmtoNWZrbHU0dTE4aDViZzcwMDRiN2w4LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwibmFtZSI6IkZyYW5rIEhhcnQiLCJwaWN0dXJlIjoiaHR0
Now, my guess is that I have to send that string to my server, and do something with it, possibly involving the "Client secret" that is associated with the App on developers.google.com. But I've been looking most of the day, and I'm not sure if what I've found is necessary - I hope it isn't
https://developers.google.com/identity/sign-in/web/backend-auth
Do I now need to become an OAuth2 programmer just to add a Sign-in with Google button?
The good news is that you do not need to learn OAuth2, you do not need to follow the backend-auth guide linked in your question. This migration actually removes the complexity OAuth2, access and refresh tokens from sign-in. Yes, there is the difficulty of learning and understanding the new and different way of securely sharing the user profile. Hopefully, after cresting over the learning curve you'll see how this makes working with a profile more simple.
JSON Web Tokens (JWTs) are now used to securely share the Google Account profile.
That big pile of text--the credential, it is a base-64 encoded and a JWT.
jwt.io has an online JWT decoder that's handy for testing and a nice writeup of working with JWTs. After decode its just a JSON object, no get methods are necessary, just access the individual fields.
All this said, you need to decide whether decode should take place in the user's browser, or on your backend server. This depends upon how you're working with the profile and your setup. Typically, you'd decode on your server after a redirect using data-login_uri in HTML or login_uri in JS.
There are a large number of JWT decode libraries available, so it's very likely you'll be able to add a JWT library, decode it and you're all set to access the individual fields in the credential.
I am trying to implement a notification system for handling notifications similar to friend request notifications. For example, I write the email of the person I want to send a friend request to. then click on send request. I am confused as to after that, what exactly should happen?
Right now I am thinking that on clicking send request, I would create a document in cloud firestore in a 'notifications' collection, which would then invoke a cloud function that sends a push notification to the user with that email. The user now has the option to accept or deny the request. Choosing any of those actions would update the notification document which will again invoke a cloud function that would add both users to each other's friends list and notify the first user.
So my questions are: -
Is this method reasonably good to be implemented in a production app since it is involving many cloud function invocations and document read and writes? Or even better question - How would you implement something like this in a production-grade app?
Is there any other method that is secure (in the sense that no one should be able to wreck this process by changing the code on the frontend) and efficient (less read/writes/invocations)?
Can this be done without creating any document whatsoever? Purely by cloud functions? Then would it be able to capture other user's response to friend request and do the necessary changes?
For the problem you are describing I would approach it in the say way you are doing, and in fact there are not that many operations going on here, since you would have 2 Firestore writes and 2 invocations of cloud functions, not to mention that the second invocation could take a long time to be fired depending on the user's actions, so you don't need to be more efficient than that.
To you final question I would say that it would be difficult to have this implemented without information going through Firestore because you need to store the acceptance of the friend request, and for the same reason mentioned above, you need to store that information somewhere, even if temporarily.
I know I'm late but maybe this will help to someone else.
My way adding sent - receive friend request system is following:
For example:
me:
{
name:'John',
id:'20'
};
stranger:
{
name:'Lucas',
id:'50'
}
When I click add friend (on stranger) I will call function:
addDoc(doc('users', stranger.id, 'receivedFriendRequests'), { user:me });
This function will add ME into his receivedFriendRequests docs so he will be able to get that docs and check users who sent request to him.
So, in notifications Component you have to just get your receivedFriendRequests` docs and map all users and make function to accept friend requests for each of them.
When you click accept you need to delete that user from receivedFriendRequests and store both users in "friends" collection. You can do it in your own way, but I give the best example, in my opinion.
I have an http function, that uses nodemailer and gmail to send emails when invoked,
I use it for a contact us form on my website,
I find that I'm able to send as many as I can from Postman, and similarly can just set up a script that keeps on firing that function without limits
I've looked everywhere to find a way to restrict access, but couldn't find anything that made sense as a simple straightforward solution
I have an app created with Firebase real-time database and I've created a few users, all with REST methods found here: https://firebase.google.com/docs/reference/rest/auth/
I can get the user info for the current user, but I would like to have a REST endpoint to fetch all the users (UID, email, displayPhoto, name, etc) or at least a user by UID. I haven't found this method in the link above.
I know that there is an SDK to do that (https://firebase.google.com/docs/auth/admin/manage-users), but I would like to do this with REST since the full app is using REST.
Does anybody know if this is possible and has the rest endpoint?
Thank you!
There is no public REST API to get a list of all users. The reason for this is that getting a list of users is considered a sensitive operation, and allowing that from client-side code would be risky.
The common way to implement your use-case is to build your own endpoint, either on a server you already control, or with Cloud Functions. There you can use the Admin SDK to get the list of users, and then return that to your caller. Make sure to limit what data you return and to properly secure that endpoint though, as otherwise you'll be putting your user's information at risk.
When working with Firebase (Firebase cloud function in this case), we have to pay for every byte of bandwidth.
So, i wonder how can we deal with case that someone who somehow find out our endpoint then continuous request intentionally (by a script or tool)?
I did some search on the internet but don't see anything can help.
Except for this one but not really useful.
Since you didn't specify which type of request, I'm going to assume that you mean http(s)-triggers on firebase cloud functions.
There are multiple limiters you can put in place to 'reduce' the bandwidth consumed by the request. I'll write a few that comes to my mind
1) Limit the type of requests
If all you need is GET and say for example you don't need PUT you can start off by returning a 403 for those, before you go any further in your cloud function.
if (req.method === 'PUT') { res.status(403).send('Forbidden!'); }
2) Authenticate if you can
Follow Google's example here and allow only authorized users to use your https endpoints. You can simply achieve this by verifying tokens like this SOF answer to this question.
3) Check for origin
You can try checking for the origin of the request before going any further in your cloud function. If I recall correctly, cloud functions give you full access to the HTTP Request/Response objects so you can set the appropriate CORS headers and respond to pre-flight OPTIONS requests.
Experimental Idea 1
You can hypothetically put your functions behind a load balancer / firewall, and relay-trigger them. It would more or less defeat the purpose of cloud functions' scalable nature, but if a form of DoS is a bigger concern for you than scalability, then you could try creating an app engine relay, put it behind a load balancer / firewall and handle the security at that layer.
Experimental Idea 2
You can try using DNS level attack-prevention solutions to your problem by putting something like cloudflare in between. Use a CNAME, and Cloudflare Page Rules to map URLs to your cloud functions. This could hypothetically absorb the impact. Like this :
*function1.mydomain.com/* -> https://us-central1-etc-etc-etc.cloudfunctions.net/function1/$2
Now if you go to
http://function1.mydomain.com/?something=awesome
you can even pass the URL params to your functions. A tactic which I've read about in this medium article during the summer when I needed something similar.
Finally
In an attempt to make the questions on SOF more linked, and help everyone find answers, here's another question I found that's similar in nature. Linking here so that others can find it as well.
Returning a 403 or empty body on non supported methods will not do much for you. Yes you will have less bandwidth wasted but firebase will still bill you for the request, the attacker could just send millions of requests and you still will lose money.
Also authentication is not a solution to this problem. First of all any auth process (create token, verify/validate token) is costly, and again firebase has thought of this and will bill you based on the time it takes for the function to return a response. You cannot afford to use auth to prevent continuous requests.
Plus, a smart attacker would not just go for a req which returns 403. What stops the attacker from hitting the login endpoint a millions times?? And if he provides correct credentials (which he would do if he was smart) you will waste bandwidth by returning a token each time, also if you are re-generating tokens you would waste time on each request which would further hurt your bill.
The idea here is to block this attacker completely (before going to your api functions).
What I would do is use cloudflare to proxy my endpoints, and in my api I would define a max_req_limit_per_ip and a time_frame, save each request ip on the db and on each req check if the ip did go over the limit for that given time frame, if so you just use cloudflare api to block that ip at the firewall.
Tip:
max_req_limit_per_ip and a time_frame can be custom for different requests.
For example:
an ip can hit a 403 10 times in 1 hour
an ip can hit the login successfully 5 times in 20 minutes
an ip can hit the login unsuccessfully 5 times in 1 hour
There is a solution for this problem where you can verify the https endpoint.
Only users who pass a valid Firebase ID token as a Bearer token in the Authorization header of the HTTP request or in a __session cookie are authorized to use the function.
Checking the ID token is done with an ExpressJs middleware that also passes the decoded ID token in the Express request object.
Check this sample code from firebase.
Putting access-control logic in your function is standard practice for Firebase, BUT the function still has to be invoked to access that logic.
If you don't want your function to fire at all except for authenticated users, you can take advantage of the fact that every Firebase Project is also a Google Cloud Project -- and GCP allows for "private" functions.
You can set project-wide or per-function permissions outside the function(s), so that only authenticated users can cause the function to fire, even if they try to hit the endpoint.
Here's documentation on setting permissions and authenticating users. Note that, as of writing, I believe using this method requires users to use a Google account to authenticate.