firebase how to temporary secure data with a pincode - firebase

data
{
"padlock": {
"open": 1432206070000
},
"boxes": [
{"owner": "bob", "amount": 23},
{"owner": "luca", "amount": 13},
{"owner": "louise", "amount": 4},
{"owner": "anna", "amount": 34}
]
}
security rules
{
"rules": {
"boxes": {
".read": "auth !== null",
".write": "auth !== null && root.child('padlock').child('when').val() > now - 15000"
}
}
}
Read and write to boxes is only for authenticated user.
Modification of boxes values only if the padlock is open less than 15 second ago.
To open the padlock for 15 seconds, just update the value with the current time.
How can i protect the padlock with a second simple auth layer? (like a client side pin code)
Is the only way to use privileged worker?
Web client securely send the pincode to the privileged worker. The worker will check the code and update the open timestamp. Add a security rule so only the worker as exclusive access to 'open'
Any idea?

I Think i found a solution just using security rules
how to protect some data from write access with a password based lock (like a pin code)
DATA
{
"boxes" : [
{"amount" : 23},
{"amount" : 11},
{"amount" : 34},
{"amount" : 3}
],
"key" : {
"oldPassword" : "xxxxxxx",
"password" : "xxxxxxx"
},
"lock" : {
"password" : "xxxxxxx",
"open" : 1432292525055
}
}
RULES
{
"rules": {
"key": {
// nobody can read the key
".read": false,
// only people who know the key can change it
// if no key exists you can stil create it
".write": "data.child('password').val() === newData.child('oldPassword').val() || !data.exists()",
// password (string) must exists and be different than the old one
".validate": "newData.child('password').isString() && newData.child('oldPassword').isString() && newData.child('password').val() !== newData.child('oldPassword').val()"
},
"lock": {
// nobody can read the lock
".read": false,
// only people knowing the key can create the lock
// to prevent partial write (without the password), only create and delete are authorized (no data update)
".write": "(!data.exists() && root.child('key').child('password').val() === newData.child('password').val()) || !newData.exists()",
// open is the creation time
".validate": "newData.child('open').val() === now"
},
"boxes": {
".read": "true",
// write only allowed for 15 sec after the padlock is open
".write": "root.child('padlock').child('open').val() > now - 15000"
}
}
}

Related

Firebase hierarchy security rules

I have a problem restricting access to the children of the object
The rules I need:
roles - read
-- UID
--- SUPUSR
---- settings = read only
--- store = write and read
My rules
"roles":{
".read":"auth != null",
".write":"root.child('roles/SUPUSR/').child(auth.uid).child('settings').child('pri_enabled').val() == 1 || root.child('roles/USERS/').child(auth.uid).child('settings').child('pri_enabled').val() == 1",
"settings":{
".read":"auth != null",
".write":false
}
If I leave it the way it is above, it inherits the "roles" rules for writing
Firebase Realtime Database Rules cascade, once you grant permission, you cannot revoke it. So if you allow write access on /roles, anyone can write to any child of /roles whether it's their own or someone else's data.
Other notes:
The current rules affect /roles and /roles/settings, which is too high in the database tree, you should be setting the rules of /roles/SUPUSR/someUserId, /roles/SUPUSR/someUserId/settings and so on.
The use of auth != null seems out of place. Should any logged in user be able to read any other user's roles? Should this only work for super users?
Some of the data would also make sense to be validated.
{
"rules": {
"roles": {
"SUPUSR": {
"$uid": {
// any data under /roles/SUPUSR/$uid is readable to logged in users
".read": "auth != null",
"nome": {
// only this user can update nome, it also must be a string
".write": "auth.uid === $uid",
".validate": "newData.isString()"
},
"role": {
// only this user can update role, and it must be one of a select number of string values
".write": "auth.uid === $uid",
".validate": "newData.isString() && newData.val().matches(/^(R&S|Admin|etc)$/)"
},
"store": {
".write": "root.child('roles/SUPUSR/').child(auth.uid).child('settings').child('pri_enabled').val() == 1 || root.child('roles/USERS/').child(auth.uid).child('settings').child('pri_enabled').val() == 1"
}
// any other keys are ".write": false, by default, which includes "settings"
}
}, // end /rules/roles/SUPUSR
"USERS": {
"$uid": {
...
}
}, // end /rules/roles/USERS
...
}, // end /rules/roles
...
}
}

Firebase database rules allow update but prevent create

How to set the database rules with "allow to update but not allow to add new record"?
I tried to simulate below but doesn't work..
My Data:
{
users:{
-randomID001:{
email:user#email.com,
status:active
},
-randomID002:{
email:user2#email.com,
status:inactive
}
}
}
Simulate in the console:
{
"rules": {
".read": "auth != null",
"users":{
".indexOn": "email",
".write":"!newData.exists() && data.exists()"
}
}
}
This line of code show mean for allow to write if new record doesn't exist and existing record exist ??
".write":"!newData.exists() && data.exists()"
Below is the test data i submit:
{
"randomID001":{"status":"inactive"}
}
I got the below error:
Simulated update denied
Please advise.
You can use validate to check if email already exists in the database this will allow only update on the existing users.
"users":{
"$userId":{
".write":"auth!=null",
".validate":"newData.child('email').val()===data.child('email').val()"
}
Firebase Realtime Database Simulator allows you to test [READ, SET, UPDATE]
It looks like dealing with firebase object.
FIREBASE DB MODEL - here is yours
{
users:{
-randomID001:{
email:user#email.com,
status:active
},
-randomID002:{
email:user2#email.com,
status:inactive
}
}
}
Try with different Locations
/users/randomID001 // exists in your DB
/users/randomID002 // exists in your DB
/users/randomID003 // not exists in your DB
CREATE
// newData(json) exists and no randomID001,002 data => FALSE
// newData(json) exists and no randomID003 data => TRUE
".write": "newData.exists() && !data.exists()"
UPDATE
// newData(json) exists and target(randomID001,002) data exists => TRUE
// newData(json) exists and target(randomID003) data exists => FALSE
".write": "newData.exists() && data.exists()"
DELETE
//You are sending only HTTP DELETE SIGNAL, NOT JSON
//Target(randomID001,002) data exists => TRUE
//Target(randomID003) data exists => FALSE
".write":"!newData.exists() && data.exists()"
next example is allowing [create,update]
You can think like "CREATE || UPDATE || DELETE".
{
"rules": {
"users": {
"$uid":{
".write": "(newData.exists() && !data.exists()) || (newData.exists() && data.exists())"
}
}
}
}
Also validation rule is good idea to be secured.
VALIDATION
...
items: {
"$itemId": {
".validate": "newData.hasChildren(['name', 'message', 'timestamp'])",
"name": {
".validate": "newData.val().length > 0 && newData.val().length < 20"
},
"message": {
".validate": "newData.isString() && newData.val().length > 0 && newData.val().length < 50"
},
"timestamp": {
".validate": "newData.isNumber() && newData.val() == now"
}
}
...
For your code maintenance, Firebase bolt is good choice.
https://github.com/firebase/bolt/blob/master/docs/language.md

Firebase read permissions

So I've set up a simple db/web form to collect some user data. Rn I am trying to figure out the rules thing but I am running into this problem - if my read flag is set to true then I can simply run this in the console
var ref = firebase.database().ref();
ref.on("value", function(snapshot) {
console.log(snapshot.val());
}, function (error) {
console.log("Error: " + error.code);
});
and expose the users which should not be the possibility. If I set read to false then I cant access the DB upfront to validate if email address is unique or not. I guess I need to achieve 2 things:
Prevent db snooping through the dev tools running any snippets
Make sure email address is unique.
p.s. My currents rules (prevent delete, prevent read, make sure POST request has certain fields):
{
"rules": {
"users": {
".read": false,
"$uid": {
".write": "!data.exists()",
".validate": "newData.hasChildren(['first_name', 'last_name', 'email', 'country', 'amount'])"
}
}
}
}
To avoid duplicates you will want a validation check in the DB rather than reading data from the client and checking (you can't trust the client).
Since there is no easy way to check for duplicate child values in a firebase base collection, you will need a separate collection to track emails and then validate your emails against that, i.e.:
{
"rules": {
"users": {
".read": false,
"$uid": {
".write": "!data.exists()",
".validate": "newData.hasChildren(['first_name', 'last_name', 'email', 'country', 'amount'])",
"email": {
".validate": "!root.child('emails').child(newData.val()).exists()"
}
}
},
"emails": {
".read": false,
".write": "!data.exists()"
}
}
}
You will then need to write the users' emails to the email collection as the users are added, e.g.:
var ref = firebase.database().ref('emails/'+email);
ref.set(uid)

Firebase Security rule

I have data in firebase in following format -
"requests" : {
"-KpPjt5jQZHBalQRxKSK" : {
"email" : "pariksheet#agsft.com",
"itemId" : "-KmazkKp5wavdHOczlDS",
"quantity" : 1,
"status" : "new"
},
"-KpZsw3KHE9oD1CIFQ4R" : {
"email" : "pbarapatre#gmail.com",
"itemId" : "-Kmb-ZXfao7VdfenhfYj",
"quantity" : 1,
"status" : "new"
}
}
Every request contains
"email" <- user's email id who has initiated the request.
"itemId" <- id of requested item
"quantity" <- item quantity
"status" <- "new" | "approved" | decline.
I am struggling to write Firebase rule which would:
allow authenticated user to access/read only requests which are raised by him/her.
allow admin user to read/update all requests.
My current rule is as follows :
{
"rules": {
".read": false,
".write": false,
"items" : {
".read": "auth != null",
".write": "root.child('roles').child(auth.uid).val() === 'admin'"
},
"requests": {
".write": "root.child('roles').child(auth.uid).val() === 'admin'", /*Only Admins can update request*/
"$rId": {
".read": "data.child('email').val() == auth.email || root.child('roles').child(auth.uid).val() === 'admin'"/*Request owner and admin can only read the particular request*/
}
}
}
}
I have maintained separate node roles which has
{
"uid" : "role"
}
I am using AngularFire2 to query Firebase in my app.
Sample code to retrieve requests with given status as below
const queryList$ = this.db.list('/requests', {
query: {
orderByChild: 'status',
equalTo: status
}
})
Thanks
Pari
I suggest you make the following changes:
In the root of the database create a new object admins
"admins": {
"<ADMIN_1_UID>": "true",
"<ADMIN_2_UID>": "true"
}
Then make changes to your security rules like this:
"rules": {
"admins": {
".read": false,
".write": false /*This ensures that only from firebase console you can add data to this object*/
},
"requests": {
".read": "root.child('admins').child(auth.uid).val()",
".write": "root.child('admins').child(auth.uid).val()", /*Only Admins can read/update all requests*/
"$rId": {
".read": "data.child('email').val() == auth.email"/*Request owner can read only the particular request*/
}
}
}

Firebase using auth.uid as key and adding rules to it and its children

I have a data structure that adds user's data to their unique id such as follows.
"users" :
{
"user_id":
{
"name":"John Doe",
"email":"email#example.com",
"account":"limited",
"avatar" : "this will be a base64 data string"
}
}
I want to deny users from listing other users and I also want logged in users to access their data based on their "user_id" which is gotten from auth.uid
I had tried some rules:
{
"rules" :
{
"users" :
{
".read" : "false",
".write" : "auth != null && !data.exists() && newData.exists() ",
".validate" : "newData.child('user_id').hasChildren(['name', 'email', 'account','avatar'])",
"user_id" :
{
".read" : "auth.uid === user_id",
".write" : "false",
"avatar" :
{
".write" : "!data.exists() && newData.exists() && auth.uid === user_id",
".read" : "auth.uid === user_id"
}
}
}
}
}
Now keeping in mind that "user_id" can be anything and it changes per user, how can I implement that? Do you have other suggestions on a way I can work this out?
You need to take a close look at the Firebase documentation found here: https://www.firebase.com/docs/security/guide/user-security.html
You need to make use of the wildcard path to represent each user like this:
{
"rules": {
"users": {
"$user_id": { //this is the WILDCARD path
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
Wildcard paths explanation: https://www.firebase.com/docs/security/api/rule/path.html
Finally, I wouldn't recommend storing the email in this way because it will be available anyway via simpleLogin.

Resources