I am trying to secure my firebase database to allow the creation of new records, but not allow the deletion of existing records. Ultimately, I plan to utilise Firebase authentication in my app as well, and allow users to update existing records if they are the author, but I am trying to get the simple case working first.
However! No matter what I try in the database rules simulator, despite what the documentation seems to suggest, the value of data.exists() seems to always be true. From what I what I can understand from the documentation, the variable data represents a record in the database as it did before an operation took-place. That is to say, for creates, data would not exist, and for updates/deletes, data would refer to a real record that exists in the database. This does not seem to be the case, to the point where I am actually suspecting a bug in Firebase, as when setting the following rules on my database, all write operations are disallowed:
{
"rules": {
".read": true,
".write": "!data.exists()"
}
}
No matter what values I put into the simulator, be it Location or Data. I have even written a small EmberJS app to verify if the Simulator is telling the truth and it too, is denied permission for all write operations.
I really have no idea where to go from here as I am pretty much out of things to try. I tried deleting all records from my database, which lets the simulator think it can perform write operations, but my test app still gets PERMISSION_DENIED, so I don't know what's causing inconsistencies there.
Is my understanding of the predefined data variable correct? If so, why can't I write the rules I want? I have seen snippets literally trying to achieve my "create only, no-delete" rule that seem to line up with my understanding.
Last note: I am trying this in a totally new Firebase project with JUST the rules above, and only ~a few records of junk data laying around my database.
Because you have placed the !data.exists() at the root location of your database, data refers to the entire database. You will only be able to write to the database when it is completely empty.
You indicate that you run your tests with only a few records of junk data laying around my database. Those records will cause data.exists() to be true.
You can achieve your goal by placing the !data.exists() rule in your tree at the specific location where you want to require that no data already exists. This is typically done at a location with a wildcard key, as in the example you linked:
{
"rules": {
// default rules are false if not specified
"posts": {
".read": true, // everyone can read all posts
"$postId": {
// a new post can be created if it does not exist
// existing posts can only be edited by their original "author"
".write": "!data.exists() && newData.exists() || data.child('author').val() == auth.uid",
".validate": "newData.hasChildren(['title', 'author', 'timestamp'])",
}
}
}
}
Related
I am using the firebase for store some users data. So now i want to delete old data with check 'last_ubdated' time < 5 min. please help for create the firebase rule for this. below is my data structure.
I have created the rule, but its not working properly.(code is below)
{ "rules": {
".read": true,
".write": true,
"$drivers":{
".indexOn": ["driverId"],
".write": "newData.exists() || data.child('last_updated').val() > (now)",
} } }
Firebase security rules can't change any data after it's been added. They only take effect at the time data is read or written by the client. If you want to arrange to delete something on a schedule, you will need another solution.
See also: Cloud Functions for Firebase trigger on time?
As Doug said, security rules can't change the data. They merely affect what (read and write) operations are allowed.
An alternative would be to use a query to only request nodes that have not expired, and then use security rules to ensure only that query is allowed. For an example of that, see my answer here: How to make data unreadable once the time indicated on its time stamp has passed?
This question already has an answer here:
does the firebase database online editor ignore security rules
(1 answer)
Closed 5 years ago.
Overview
When using the Realtime Database in Firebase, I am able to edit and bypass rules. I see how this is convenient in some cases, but I would like to apply rules to manually submitted data as well.
Example
Here's the most simple write rule to disable writes anywhere. With the rule simulator, I am not able to write, as expected.
However, even once I've saved the rule, I can still write in my database.
Today is my first day using Firebase rules. Am I confused about rules or is there no option to disable bypassing rules in the manual editor?
You will be able to write to the database manually from the console(no there is no option), but using the rules above ".write": "false", it means that the end user wont be able to write to the database.
The person adding manually to the database, is usually the admin. That is why even if it is write:false it will still add to the database.
But if for example you have this:
Class
randomid
Keys:values
Then the user that will create the class in his phone won't be able to send data to the database since write:false
Even if you have this:
{
"rules": {
".read": "false",
".write": "false",
}
}
You will still be able to see the data in the console, but the end user won't be able to read or write to the database.
Remove the last comma.
{
"rules": {
".read": "false",
".write": "false"
}
}
and publish changes, than test.
Note that you can add values anyway, because you own that database and use it from console. If you use it from a SDK (Android, iOs, Node, etc), you won't be able to write data.
I see that .validate rules can be used to check if certain data should be written depending on certain condition, such as:
".validate": "newData.isString()"
But is it possible to correct or modify the actual data? For example if we want a string to be saved always, it would be something like this:
".validate": "newData.isString() ? true : newData = ''; true"
If not, what would be the best alternative for this use case?
No, that is not the point of the Database rules. .validate will only check for the format.
If you want to modify the uploaded data, you have a nice example over here:
https://firebase.google.com/docs/functions/database-events
Integrating Cloud Functions is fairly easy and does exactly the job what you want.
This talk mentions time-expiring data using Firebase rules at 22:55
https://www.youtube.com/watch?v=PUBnlbjZFAI
How can one do this ?
I didn't find any information regarding this.
I recommend two solutions.
1) Use cloud functions to record a message path and the date it was posted. Then every hour sort that list by date, pick all the expired ones, and create a deep update object to null out every expired message. Nowadays you can use Cron Scheduler to handle the periodic flush.
2) Make a rule that says anyone can delete expired messages and make it so that clients automatically delete expired messages when they are in a chat room.
Written here: https://firebase.google.com/docs/database/security/securing-data
You can't have it auto delete your data but you can make them unreadable (which is the same thing from the user standpoint). Just send a timestamp child field with you data and check against it.
{
"rules": {
"messages": {
"$message": {
// only messages from the last ten minutes can be read
".read": "data.child('timestamp').val() > (now - 600000)",
// new messages must have a string content and a number timestamp
".validate": "newData.hasChildren(['content', 'timestamp']) && newData.child('content').isString() && newData.child('timestamp').isNumber()"
}
}
}
}
Same question here.
You can't do it using firebase rules. You should either have a NodeJS backend removing your old data or clients doing it for you. For example, before a client retrieves data, he could remove old data.
What's happening is that usually the first time I authenticate a user after enough time has passed that the session has expired my requests for data that the user should have access to are denied. The requests will start working eventually with no actual rules or code changing. It can take from 2 to 10 minutes but will eventually right itself.
I don't have hard data on this; it's just something I've observed.
I have no idea what I can do about this. Is anyone else seeing this? Is this a known bug? I've search but haven't found any other accounts of this happening.
Thanks.
here are the rules:
{
"rules": {
"users": {
"$user": {
".read" :"$user == auth.id || data.child('email').val() == auth.email",
".write":"$user == auth.id"
}
},
"todos":{
"$list":{
".read":"data.child('members').hasChild(auth.id)",
".write":"newData.child('members').hasChild(auth.id)"
}
}
}
}
By default, your auth tokens live for 24 hours, so if you're seeing security errors before then, it's probably not related to your session. To verify this, you can attach a callback to tell you when your session has expired. See:
https://www.firebase.com/docs/javascript/firebase/auth.html
I suspect what's going on here is simply that the data your rules are depending on is changing and causing writes to succeed some times, and fail others. This is the intended behavior of Security Rules in Firebase. For example, if someone was added / removed from /todos/blah/members/ it would affect your ability to read at /todos/blah
One odd thing about your rules is that you appear to be allowing anyone to write to /todos/$list as long as the data they are writing contains a member list that contains the writer's user id. I suspect this is not your intended behavior. Perhaps you meant to make the write rules depend on the data that was already in Firebase rather than new data?