How to protect public zones and how to set quotas for users on Firebase? - firebase

Let's take a simple example.
We have the /users node, protected by a rule per user.
Then we have the /movies node and each user that watched a movie, the app will add the userid to this movie.
Since users can write to /movies, how can I protect a malicious user from ref.remove() it? I can solve it by adding the movie to the /users/$user and then create a FB function to add it to /movie. Feels strange.
Simply put, how to protect public areas?
Since an authenticated user can write into his area under /users, how do I set quota to prevent malicious user from consuming all my bandwidth, storage, etc?

Related

Have one user signup another user with custom fields in firebase/flutter

I am trying to determine if the following scenario is possible with flutter and firebase:
we have users within the company who will be given access to the app, where on the homepage will be a signup another user button where they enter in that user's email and password, they get signed up, and then the original user specifies custom fields for the 2nd user, such as company name, role, position, etc.
Is this possible with flutter and firebase?
Have asked the flutter google group and was told about custom authentications, but from what I see that is just an external authentication system and doesn't show me how to let one user create another users profile with fields.
Any ideas?
The first thing to consider is whether those properties need to be in the user profile at all. The user profile is sent with every request, and should only contain information that is relevant for securing access. If you have additional information to store about the user, you should store it elsewhere (such as in one of Firebase's databases) using the UID of each user as its key.
Assuming that the information is about security (such as the role seems to be, there is no secure way to let one user set security properties (typically referred to as claims) from client-side code. As soon as this is allowed from client-side code, anyone could set such properties for anyone else. That's why setting custom claims for a user is only possible with Firebase's Admin SDKs, which are designed to run in a trusted environment - such as your development machine, a server you control, or Cloud Functions.
There are a few other options, but it's important to realize they're all implemented on top of the above approach.
There is an experimental extension that allows you to set auth claims by writing a document into Firestore, which something like this (JavaScript syntax, but the Flutter code will be similar):
db.collection("user_claims")
.doc("abc123")
.set({
role: "admin",
groups: ["example1", "example2"],
});
Now of course you'll want to make sure that you secure writing to the user_claims collection, as otherwise you'll end up with the same security risk I mentioned in the first paragraph, where everyone can claim any role they want.
Alternatively you can write your own server-side API (for example on Cloud Functions) that you expose to your application, and that then calls the Admin SDK. Here too, it is important to secure access to this API, to ensure only authorized users can call it.

Cloud Firestore Role Based Access

I'm trying to implement role-based security for Cloud Firestore. Am I understanding correctly that users retrieving stories in Google's example at https://firebase.google.com/docs/firestore/solutions/role-based-access would see the roles other users have?
How would one design against that?
I assume by using another collection & using Get?
Tad vague, but...
I am implementing role-based access in an app, but not following the example, for the very reason you mention: if a user can read a document, then they read all of the document.
My approach is a bit less direct.
The roles are stored in more secure records where only someone authorized to create the roles has access.
A Cloud Function is used for a user to fetch role information - that
way the user does not have direct access, but the secure back-end can
validate and "filter" the data appropriately (in this case, whether they are "managers" of a business property)
Another Cloud Function adds role information onto the Users account
Token as customClaims (has to be done in secure environment, not client)
Security rules validate access against the customClaims - which all
happens in a secure environment (no need to trust the browser)
More convoluted, but it does control role visibility.

how to make singups and signins with different group of users

I am developing an app for my college and there are different types of users called students ,teachers , hod's
etc. When they login, how do I know a teacher logged in, or a student logged in? Is there any function in firestore for role based signups and signins?
I was thinking that when a teacher signs up, I will add a tag end of her uid.username that if username is 'DANIEL' while signup, I will add a tea for teachers and stu for students at the end of the name what they provided.
So when they login i will get the uid and do the string manupulations and get the last three letters so that i can know who logged in so that i can show different UI to Different types of users
Is there any best way to do like this ?
while singning up user enters his username example:"daniel"
i will update that username in uid.username like this "daniel-stu"(if student signed up),"daniel-tea" if techer signsup.
Storing this information in the user's display name can work. You can read it back from there next time, and take action in your application's client-side code. But note that this means that any user can change their role, since they can also call the same code to update their profile. If that is not a concern for your app, then this approach sounds like it would work.
If malicious users should not be able to change their role, then you shouldn't set that role from the client-side application code. In that case, you can set the role from a server (or your development machine, or Cloud Functions) using the Admin SDK. Since the Admin SDK runs in a trusted environment, it has expanded privileges and can update the profile of any user. So the Admin SDK could update the display name of the user in the same way you have in mind.
But this still isn't secure, since you're still setting a property that anyone can modify for their own profile. Again... if that is no problem for your app that is fine, but if the use-case requires that you can rely on the property to be correct, we have to keep looking elsewhere.
The Admin SDK can set additional so-called claims on a user profile that client-side code can't modify. Such claims are for things that affect the permissions of the user, such if the user is an admin, or what role/group your users belong to. This sounds quite close to what you are describing, so can also be used. And this time, only your code that runs in a trusted environment will be able to do so.
Finally, you could store the additional information about a user in the database. It's quite common to have a collection (Users or Profiles) in the database, where you store a document for each user (with the document name being User.uid). You create the document when the user first signs in, and update whenever you need to. You can do this from the client-side code (if there is no need to control what gets written), or from code that runs in a trusted environment (such as your development machine, a server you control, or Cloud Functions) if you do need to keep control. A big advantage of this approach is that all users can potentially see the information in this collection, where the client-side Authentication SDK only allows a user to read their own user profile.
For more on this, see:
Adding new data to firebase users (in which I essentially list the same options with fewer words)
Add extra User Information with firebase (store the information in the realtime database)
Associate Firebase Users to Database Records (also using the realtime database for the additional information)
Cloud Firestore saving additional user data
this video explaining custom claims
and many more previous questions on this topic

Getting another user's PhotoURL in Firebase

I'm using the Firebase 3 SDK with AngularFire.
I can use the AngularFire code below to get the photoURL of the currently authenticated user:
$firebaseAuth().$getAuth().photoURL;
But, given the UID of another user, how do I get that user's photo, so I can display it on the page?
I'm assuming any user can read the PhotoURL of any other user (that makes sense since the PhotoURL is to your public picture) But I can't find out how to look it up for arbitrary users. Am I being stupid and missing something obvious?
Firebase alone won't allow you to access other user's photoUrl. Depending on the provider, you can use their respective APIs to get other user's photos.
For example, if your provider was Google OAuth2, you can ask for additional scope of contacts, calendar, etc (a lot of them have user/photo meta data that gets returned) and the make API calls with the user's google access token to fetch more info.
An alternative solution might be to cache the photos of people who have logged into your service. So basically you would be saving all the photoURLs of people who have logged in. There several downsides to this approach though.
You don't have photos for people who have not logged in yet.
This might be against the provider's user privacy policy.
The photo can be outdated unless you are proactive about syncing the photoURL.

Facebook SDK - access a public album by id without authentication

I develop an ASP.NET website. It will contain text articles and some of them will contain pictures from my facebook account above and beyond the text. Note that I'm going to use only the public albums from my account.
So I created a sql table and binded the articles, the albums and the photos (in fact the IDs of all of them). I already used facebook api sdk and it was a great library.
Obviously any visitor of my website (even he doesn't have a facebook account) mignt be able to see the articles and the pictures withount visiting facebook and without authentication via facebook oAuth to access them.
Well here are the questions:
1) How do I get the photos a public album contains by album id and user id without authentication? (I don't know, maybe I should use the other parameters than album id and user id)
2) How do I get the properties (name, id, etc) of a public album?
With out an access token there's very little you can get from the graph api.
Just try yourself by directing your browser to: http://graph.facebook.com/YOU_USER_ID.
You can also check the fields/connections tables in the User object documentation, where it says "No access_token required" in the Permissions column (3rd) you can get with out a token.
If you want to get other data of yourself and serve it publicly on your site you have two options:
Use the server-side authentication flow, get a long lived access token (60 days), save that and use it for the following 60 days to get your data from facebook.
Then, when it gets expired go through the authentication process again.
It will just be you who needs to go through it, not your users, and only once every 60 days.
Log in yourself, authenticate against your app, get all the data and persist it on your db, then just present that to your users.
You'll need to update things every once in a while.
Edit
The server side authentication flow guide has an example written in php.
It's a simple example which does not cover all scenarios but it's a good start.
I have implemented this in python and java but it's not something that can easily be shared since it spans across multiple requests and states, and so I'll just describe the flow I think that you should use:
Inside facebook you go to your canvas app
Facebook will make a POST into an iframe with your canvas url
In the post data you will get a signed request, decode it and check if it has an access token, if so check when it expires. If all is good save that token and the auth process is over, otherwise:
Redirect the user to the oAuth dialog along with your redirect url and permissions that you require.
After you allow your own app you will be redirected to your "recirect_uri" with the code parameter (in the querystring).
Exchange the code for an access token against the facebook servers and save the token.
You can then redirect yourself to the canvas app or just stop there.
That should do it for a long lived access token which you can then use for 60 days.
As for persisting your fb data on your own db, it's a pretty trivial operation to save data on a db, and it all depends on what data you want to save, how you need to encode/use it (json, xml, plain text).
For example, let's say you want the display your own photos, then after you get the token (as described above) just query from your server for your photos by issues an http request to: https://graph.facebook.com/me/photos?access_token=XXXXXX.
You should get a json encoded result, iterate over that and save each picture as a record on your db.
To retrieve list of user's albums you need to issue next GET request to Graph API:
https://graph.facebook.com/me/albums?access_token=...
And to retrieve list of photos:
https://graph.facebook.com/ALBUM_ID?access_token=...
But you cannot read user's albums (and photos) without authentication and requesting user_photos permission.
According to album documentation:
To read an Album you need
Any valid access token if it is public and belongs to a Page
The user_photos permission if it belongs to a User
The friend_photos permission if it belongs to a User's friend
So generally you have only two options to achieve the result you want:
Use Facebook Page to store all the Albums/Photos you want to display on site
Read 'em using Application access_token.
This will allow you to completely bypass authentication flow at all.
Use your personal account to store Albums/Photos
Authorize application (client-side/server-side) and grant user_photos permissions
Extend access_token for your user and store it
Use your personal access_token to access your Albums/Photos

Resources