I'm new to firebase and I want to do some rules and I don't know how to do it well. If someone can help me and explain to me how they work. That would be nice! So let's start!
This is my realtime database: Image of Database
And what I want to do is that only registered users in the app can read messages and user information. Also only that you cannot delete/edit a message if you aren't the user that sent the message. The same for user information if you aren't the user you can't modify anything only read. Sorry for my English.
How can I do that? With Firebase Rules.
My actual rules are:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
I've tried with internet examples and StackOverflow examples but I couldn't have it done. So I left it like this.
So,
First: In rules you have three standard parameters: "read","write" and "validate". You can build you rules to suit you database schema. Let`s do it:
{
"rules":{
"Messages":{
// we will ad rules here leter
},
"Users":{
// we will ad rules here leter
},
".write":false,
".read":false
}
}
Now we can set diffrent rules for "Message" node, and different for "Users" node. Last parameters are for root, we dont want user to set new node or read them, we want only to allow them read/write in upper two nodes.
When user will be trying to read from Message nodes, rules will check "Root/Message" and look for rules there, rules in "Users" block wont affect this operation.
Rules working cascade, this mean that if user find ruleswhich allow him to write, write operactions will be accepted by database, even if lower will be rules with forbit this.
In firebase rules you can use plenty of functions. First let`s protect "Users" node.
to allow write only for authenticate user we will add something like this:
"Users":{
$uid:{
".write": auith.uid == $uid,
".read": auth != null,
},
".write": auth != null
}
With $ sign we can create variable, when users try to write/read in Root/Users/1234, $uid will take value 1234. With "auith.uid == $uid" we only allow user to write in their own nodes
. We should also set write rules lower (in "Users" node) to allow users to add new child to this node.
For "Message" rules we will use hasChild() method, something like this:
"Message":{
$messageUID:{
".write": data.child('uId').val() == auth.uid,
".validate": newData.hasChild('message') && newData.hasChild('name')..
},
".write":root.child("Users").haschild(auth.uid),
".read":root.child("Users").haschild(auth.uid)
}
Here we`re setting that only user whose uid is in uId property can write in $messageUID node. ".validate" rules are checking if data after operations will having message child and name child (you can add more child ).
Rule ".write":root.child("Users").haschild(auth.uid) will only allow to write for user whose id exist in Users node.
All together we have:
{
"rules":{
"Messages":{
"$messageUID":{
".write": "data.child('uId').val() == auth.uid",
".validate": "newData.hasChild('message') &&
newData.hasChild('name')"
},
".write": "root.child('Users').hasChild(auth.uid)",
".read":"root.child('Users').hasChild(auth.uid)",
},
"Users":{
"$uid":{
".write": "auth.uid == $uid",
".read": "auth != null",
},
".write": "auth != null"
},
".write":false,
".read":false
}
}
I wasn't tested this rules so maybe you need to change something, but now you should better understand how to use rules and what you can do with them. Ask if something will be wrong
Related
Am using the firebase database as my storage. While signing up am storing the username for validating the uniqueness of the username. I declared firebase security rules as follow,
{
"rules": {
".read": true,
".write": true
}
}
And my database structure is as follow,
Users
o**kcarw***27p**enV**UcB3***
Email: "testing#mail.com"
UserName: "GokulNew"
But if I declare as above am getting a firebase warning as "Your project's Realtime Database "Project" has insecure rules ".
So later I changed the security rules as follow,
{
"rules": {
".read": "auth !=null",
".write": "auth !=null"
}
}
If I declare as above the security warning is not showing but it is not allowing me to signup due to the security rules. So again I changed the rule as follow,
{
"rules": {
".read": "auth !=null",
".write": "auth !=null",
"Users":{
".read": true,
".write": true
}
}
}
After this, it is allowed me to signup but a security warning is showing. How can I avoid the security warning and at the same time I need to validate the username while signup.
And below is the Java code for signup
Query usernameQuery = FirebaseDatabase.getInstance().getReference().child("Users").
orderByChild("UserName").equalTo(upperCaseChar(username));
usernameQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.getChildrenCount() > 0) {
usernameLayout.setError("Username is already taken");
vibrator.vibrate(VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE));
dialog.dismiss();
Toast.makeText(RegisterActivity.this, "Username is already taken, Choose new one", Toast.LENGTH_SHORT).show();
} else {
//sign-up and storing the data to firebase
}
}
}
Hope my requirement is clear and thanks in advance,
Your rules should follow the principle of least privilege, meaning they allow exactly what your code needs and nothing more. Since the code you shared performs a query on /Users, you want to secure for that query, which would look something like this:
...
"Users": {
".read": "query.orderByChild == 'UserName' &&
query.equalTo.length > 0"
}
...
This only allows (if it works, because I didn't test the length check) reads on /Users that query on UserNames and specify an equalTo value, so that matches your code.
I'd recommend considering another data structure for this though, as your current code may not work when multiple users try to claim the same name around the same time. To make that work, you should introduce a top-level node where you use the username as the key and then use a transaction to write there, and in security rules ensure a value can only be written if non exists yet.
For more on this, also see these previous questions about unique usernames.
I have just added security rules to my Firebase project such that reading is public and writing is only permitted for authenticated users. This is the rules' json on Firebase:
{
"rules": {
"Country" :{
".read": "true",
".write": "auth !== null",
}
}
}
There is no problem with reading at all. Writing, however, cannot be done unless a new parent is added; I use db.push() and it works greatly. Whenever some modification on data that already exists is done I get "Permission denied" in the logcat.
I have tried to do the following but it still doesn't work:
{
"rules": {
"Country" :{
".read": "true",
".write": "auth !== null && (data.exists() || !data.exists())",
}
}
}
How might this issue be solved? it will be really tiresome to delete every data the user needs to modify and re-pushing it since the application is really huge.
My firebase database has a child which is name is Messages and it has children user_id and also it has children which are title and timestamp such as:
my firebase database
Messages
user_uid_1
Title
timestamp
user_uid_2
user_uid_3
...
I want to add a addChildEventListener for Messages to determine if there are any change in Messages. this is very easy with this code:
myRef.child("Messages").addChildEventListener(new ChildEventListener()...
how about firebase rules. if I made it public it works. but if I do like that child listener NOT working what should I add to my rules
{
"rules": {
"Messages":{
"$uid":{
".read": "data.child('timestamp').val() > (now - 18000000)",
".write": "auth != null"
}
},
"$other":{
".read": true,
".write": "auth != null"
}
}
}
I want to read only messages from the last 30 minutes can be read so that I've added ".read": "data.child('timestamp').val() > (now - 18000000)",.
I think I should add something between "Messages" and "$uid" to addchild listener correctly.
thnks!
Firebase security rules are enforced when you attach the listener. If you're allowing reads on /Messages/$uid, then a listener on /Messages will be rejected since you have no read permission on that level.
This is known as rules are not filters in the Firebase documentation, and means that you cannot use security rules to filter data. It has been covered quite a bit here on Stack Overflow already, so I suggest you check out some of the previous questions. The oldest answer I can find is this one.
I have an android app that people can write something on chatbox.
They login with google account. And i have their user id which is shown below by $uid
But if there will somebody writing stupid things i want to prevent this person's writing ability.
So how can i make this by using this body. Or what is your suggestion?
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
source: https://firebase.google.com/docs/database/security/
Updated Answer
First, you have to change your banned user JSON model to follow format.
Path pattern
/banned-users/$userid: true
From above image
/banned-users/fasjdkflksdflad: true
now change your rules to the following way
{
"rules": {
"messages": {
"$messageId": {
".read": "auth.uid != null",
".write": "auth.uid != null && !root.child('/banned-users/'+auth.uid).exists()"
}
},
}
}
Say you are adding messages to the /messages path with each messages id as $messagesId then your /messages path looks like below
{
"messages": {
"-KTKvywjwDv4RpYjQglu":{
"text": "Hey Guys..."
},
"-KTKvywjwDv4RpYjQglu":{
"text": "How you doing ..."
}
}
}
Explanation
According to the rules, any logged in user can read the /messages ".read": "auth.uid != null", defines that.
To write to message to /messages path, then firebase check for if the (user is logged in AND /banned-users/user-id path exists) in firebase. As auth.uid is internal firebase variable used when rule validation. ".write": "auth.uid != null && !root.child('/banned-users/'+auth.uid).exists()" defines that.
you can ignore .validate you can achieve this by just using .write.
old answer
You cannot do it with just security rules.
First, you have to use Firebase cloud functions.
Create database trigger on the /chats database path. When the new message contains stupid things then you can delete it right away and you can get the user ID and save it to some other path say /banned-users/<userid>
Now you can write the .validate rule to check current messaging userid is not on the banned list. Using
".validate": "!root.child('/banned-users/'+$uid).exists()"
If you have to completely disable user account then you have to use Firebase Admin API.
You do not need to do this in rules. You can just disable that person's userID in the "Authentication" section of the FirebaseConsole
Screenshot attached below as sample
This would be much easier compared to adding into the rules where you have to enter the userID manually anyway.
I cannot set value to my Firebase Database using setValue(). In logs it returns me setValue at ... Permission denied. I checked my rules:
{
"rules": {
".read": "auth == null",
".write": "auth == null"
}
}
Try changing your rules to the following and it'll work.
{
"rules": {
".read": true,
".write": true
}
}
As per Frank van Puffelen's comment your rules require the user is not authenticated.
You can read more about the authentication rules here for other options if you need more secure authentication
Hope this helps you
Firstly your user must be authenticated as Firebase provide lots of platforms to make user authenticated with it. Example - Google, Facebook, Twitter etc.
As user got authenticate by firebase console he/she get access to relevant database and storage. You can also make a user as a guest by using Firebase anonymous authentication.
By doing authentication every user gets a UID using which you can use to give access to them by writing rules if you want different rules for different users.
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
By default you will get something like this in your database rules section :-
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
This simply means that if the user authenticated then only give them read and write access. Apply to all users.
By doing something like this, you are making your database accessible to everyone and also those people who are not using your product.
{
"rules": {
".read": true,
".write": true
}
}
You can do this for testing purpose of your product, but this is not a secure way.