I got a JSON data structure like this:
recipes
LZogi4JdMk_V5vLK_aA
title: 'firste recipe'
LZoh4QphqHknuvda0-f
title 'secound recipe'
I want to make a rule (validation) for the title in each recipe. I have tried doing this:
"rules": {
"recipes": {
".write": "auth != null",
".read": "auth != null",
"$title": {
".validate": "newData.isString()
&& newData.val().length > 0
&& newData.val().length <= 20"
}
}
I think I have to get into each object in the array recipe but i'm not sure. Can anybody help?
According to firebase docs and samples $ is used to represent ids and dynamic child keys, currently you are treating $title as if it was the ID of each recipe, so your rules should instead look something like this:
"rules": {
"recipes": {
".write": "auth != null",
".read": "auth != null",
"$recipeId": { //example: LZogi4JdMk_V5vLK_aA
"title": {
".validate": "newData.isString()
&& newData.val().length > 0
&& newData.val().length <= 20"
}
}
}
Here's the link to firebase docs:
https://firebase.google.com/docs/database/security/securing-data#structuring_your_rules
Related
I have defined a realtime database rule as follows:
{
"rules": {
".read": false,
".write": false,
"devices": {
".read": "auth.uid != null && query.orderByChild == 'ownerUid' && query.equalTo == auth.uid",
"$device": {
".read": "data.child('ownerUid').val() == auth.uid",
"nickname": {
".write": "data.parent().child('ownerUid').val() == auth.uid",
".validate": "newData.isString() && newData.val().length < 30"
},
"ownerUid": {
".validate": "root.hasChild('users/' + newData.val())"
},
... additional fields here
}
}
}
}
In my web application, using reactfire and firebase npm modules, I have queried for a device as follows:
const devicesRef = useDatabase()
.ref(`devices`)
.orderByChild('ownerUid')
.equalTo(user.uid);
const { data: devices, status } = useDatabaseListData<Device>(devicesRef, { idField: 'id' });
This appears to work, but if I look in the network tab, I can see all of the data come back, not just the data that is supposed to come back. The data returned to my code is the data that I would expect.
Note in the screenshot below that all data comes back, even data that does not have ownerUid defined.
I am using the example from the documentation almost exactly: https://firebase.google.com/docs/database/security/rules-conditions#query-based_rules
Am I doing something wrong? or is this a bug in Firebase?
I discovered the solution after upgrading my firebase client version and getting some new errors from it. It turns out the issue was that I was missing an index on ownerUid.
The new rules look like this:
{
"rules": {
".read": false,
".write": false,
"devices": {
".indexOn": ["ownerUid"],
".read": "auth.uid != null && query.orderByChild == 'ownerUid' && query.equalTo == auth.uid",
"$device": {
".read": "data.child('ownerUid').val() == auth.uid",
"nickname": {
".write": "data.parent().child('ownerUid').val() == auth.uid",
".validate": "newData.isString() && newData.val().length < 30"
},
"ownerUid": {
".validate": "root.hasChild('users/' + newData.val())"
},
... additional fields here
}
}
}
}
appreciate this looks like this is been answered various times for individual requirements. Completely new to Firebase and I want to get some insight into this. I have been presented with the message from Firebase.
We've detected the following issue(s) with your security rules:
any logged-in user can read your entire database
any logged-in user can write to your entire database
My current rules look like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"items": {
".indexOn": "ownerId"
},
"events": {
".indexOn": "ownerId"
},
"contacts": {
".indexOn": "ownerId"
}
}
}
Based on the documentation, Do I simply need to do this?
{
"rules": {
".read": "auth != null && auth.uid == $uid"
".write": "$user_id === auth.uid",
"items": {
".indexOn": "ownerId"
},
"events": {
".indexOn": "ownerId"
},
"contacts": {
".indexOn": "ownerId"
}
}
}
Will users still be able to access their own (previously) written data prior to making the change while enforcing the security rules from Firebase.
Apologies if this a silly question, but got a lot of data which I cannot let users not have access to.
Thanks
As firebase documentation says:
Sometimes, Rules check that a user is logged in, but don't further restrict access based on that authentication. If one of your rules includes auth != null, confirm that you want any logged-in user to have access to the data.
So you have to get rid of this part down under the rules part:
".read": "auth != null",
".write": "auth != null",
And use any of these approaches: Content owner only, Path-delineated access or Mixed public and private access.
For example:
{
"rules": {
"products": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
".indexOn": ["creatorId", "isActive"]
}
},
"stores": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
".indexOn": ["creatorId", "isActive"]
}
},
"orders": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
}
},
}
}
I've been a while working with firebase and I love it but today I'm working on security rules and I'm getting an error with simulator, my code looks as below:
{
"rules": {
"users":{
"$uid":{
".read": "auth.uid != null",
".write": "auth.uid != null",
".validate":"newData.child('profile').child('userName').isString()&& newData.val().length < 15"
}
}
}
}
The error appear just when i add the lenght validation. When I do:
{
"rules": {
"users":{
"$uid":{
".read": "auth.uid != null",
".write": "auth.uid != null",
".validate":"newData.child('profile').child('userName').isString()"
}
}
}
}
Works fine, any idea why this is happening, I have readed the documentation on: https://firebase.google.com/docs/database/security/securing-data and many other examples and I just can't find the error. Thank you su much in advice and happy coding.
You can add validation like this to your field as per this example.
{
"rules": {
"users": {
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid",
".read" : "$user_id === auth.uid",
"familyName" : ".validate": "newData.isString() && newData.val().length > 1 && newData.val().length < 100",
"givenName" : ".validate": "newData.isString() && newData.val().length > 1 && newData.val().length < 100",
"age" : ".validate": "newData.isNumber() && newData.val() > 13 && newData.val() < 110",
"email": {
// an email is only allowed in the profile if it matches
// the auth token's email account (for Google or password auth)
".validate": "newData.val() === auth.email"
}
}
}
}
}
Ok I have solved the correct syntax:
{
"rules": {
"users":{
"$uid":{
".read": "auth.uid != null",
".write": "auth.uid != null",
".validate":"newData.child('profile').child('userName').isString()&& newData.val().length < 15"
}
}
}
}
I'm clearly missing some fundamental aspect of firebase security, because this shouldn't work. I would expect it to throw a validation error when attempting to push invalid data. (Inserting a new node into /nodes)
Rules:
{
"rules": {
"nodes": {
".read": "auth !== null && auth.provider === 'google'",
".write": "auth !== null && auth.provider === 'google'",
"user": {
".validate": "newData.val() === auth.uid"
},
"ts": {
".validate": "newData.val() <= now && newData.val() >= (now-1000*60*60*24)"
}
}
}
}
Then in my console I try to intentionally insert invalid data:
ref.child('nodes').push({
'user': 'abc',
'ts': 123
}, function(err){console.log(err);});
Which logs null, and when I check my database it was inserted, no validation errors! I know I've got something fundamentally wrong, because a validation rule right after the .read and .write rows of the following disallows any writing. .validate": "newData.hasChildren(['user', 'ts'])",
{
"nodes" : {
"-KAgH0BLneWfGu8NymBo" : {
"ts" : 123,
"user" : "abc"
}
}
}
Whoops. Missing "$node_id"
{
"rules": {
"nodes": {
"$node_id":{
".read": "auth !== null && auth.provider === 'google'",
".write": "auth !== null && auth.provider === 'google'",
"user": {
".validate": "newData.val() === auth.uid"
},
"ts": {
".validate": "newData.val() <= now && newData.val() >= (now-1000*60*60*24)"
}
}
}
}
}
The following are my Firebase security rules:
security-rules.json
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
}
}
}
}
It works fine when my path ends with the users directory. As in:
https://my-firebase.firebaseio.com/users/my-user-id.json
But when I try to post directly to a subdirectory, as follows:
https://my-firebase.firebaseio.com/users/my-user-id/settings.json
it doesn't work.
Question
What do I need to do to the security-rules.json file (or anything else) to be able to write directly to a user's subdirectory?
Edit:
Someone suggested, "just extend your rule to include settings." So I tried this:
security-rules.json
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
},
"settings": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
}
}
}
}
Which throws the following error:
9:30: Unknown variable '$uid'.
10:31: Unknown variable '$uid'.
This works in the simulator:
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
"settings": {
}
}
}
}
}
After further testing, I found the security rules contained in the OP also work in the simulator:
security-rules.json
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
}
}
}
}
There is no need to add additional rules for writing deeper into the node tree. The highest level permissions are sufficient.
Aside: My problem appears to be something other than the security rules I'm using. I must do more research, experimentation and testing.