I have a simple app I am trudging through learning how to make, it only displays a list of data that I upload periodically for discounts and coupon deals. There is no user data gathered, so I don't see a need for authentication or to log in. However as I learn and read about about storing and retrieving data, it seems I might have to. Specifically when it comes to my firebase realtime database. It is telling me my rules are insecure having both read and write set to true for public. I understand the "write" being unsafe, but is there a problem with letting the "read" function be set to true for anyone if I'm not storing any personal data? Is there any way for me to say "anyone can read, but only I can write, but I don't want everyone to have to create usernames and passwords" or is that illogical thinking and I should just make a login screen? Thank you for any insight.
Edit: I currently put my coupon data into the database via a short standalone javascript program I wrote that takes a csv file I write and writes it to the database. If I change write to false for all, I'm afraid that will prevent my program from writing. So I guess in order to keep using my program to write the data I'd have to have SOME kind of authentication, right? Very good to know I can leave the read to true for the public, thank you.
"rules": {
".read": true,
".write": true,
"deals": {
".indexOn": ["indexStore", "promoCode"]
},
}
Yes! Here is how you can do it:
Just change the ".write": true to ".write": false. That will do it
Related
EDIT
I've been doing more research on this topic and the answers down below have been VERY helpful! But I also just wanted to add this to anyone who might come across this page who, like me, is still struggling to understand how to install authentication into your app. (Of course, OAuth and Local authentication are very good routes, but if for some reason you can't do that, take a look at the link:)
https://security.stackexchange.com/questions/8596/https-security-should-password-be-hashed-server-side-or-client-side
My original question is below
I'm VERY new to the app security part of iOS development. I have an app that should be password locked and I wanted to see the best way to secure it. So here's what I was thinking:
the user creates (or is provided with) a password
let password = "password"
I use the .hash of that password to store it in a server
When and if the user needs to sign back in, they type in the password, and the app pulls down the hash number from the server and checks it against the .hash of what they just typed in
let passwordString = textbook.text
if passwordString.hash == hashPulledFromServer {
//log in
} else {
//failed
}
Is this the best way to do this? I've read that hashValue doesn't always produce the same value which of course wouldn't make it possible for this sense. But is this a secure way to transfer data to a server and use it to check on a password at a later date?
It is too difficult to give a detailed answer to your question. Information Security is an enormous subject.
Wherever possible you should rely on existing solutions and implementations. E.g. can you use OAuth or OpenID so that your app never needs to deal with passwords? Can you use the local authentication framework if you just want to secure local access to the app?
The short answer to your question "Can you use .hash?" is NO
.hash is used to create a hash for an object that can be used to aid lookup in collections like dictionaries and sets.
It is computationally simple so that it can be calculated quickly. It does not go to any lengths to prevent hash collisions (two different objects hashing to the same value). It has these characteristics because it is expected that the function will be used a lot (each access to a dictionary for example) and collisions don't really matter; in-memory collections are quite small and collisions can be handled easily.
This is the opposite of what you want in a cryptographic password hash, such as scrypt:
you want the hash function to be relatively slow and computationally expensive to slow brute force attacks; passwords are not hashed/checked very often so this doesn't matter in the normal course of things
You don't want collisions; a collision will result in an incorrect password being accepted as correct
I've created a new project on Firebase, and created a Realtime Database in there. When asked about the security rules for my database, I selected to Start in test mode.
Now the security rules of my database in the Firebase console show up as:
{
"rules": {
".read": "now < 1622790000000", // 2021-6-4
".write": "now < 1622790000000", // 2021-6-4
}
}
What do these rules mean? And how can I change them to be more secure?
It's been a month since I created my Firebase Realtime Database, and I now got a message:
Your project's Realtime Database '' will start denying client requests unless you update your security rules
These default test mode rules are a simple catch-all that allows everyone in the world to read from and write to your database until a given date.
Let's break the rules down to see exactly how they work:
The ".read" and ".write" nodes immediately under "rules" determine who can read/write the data in the entire database.
The now variable is automatically set by Firebase to be the current time on the server. This value is in milliseconds since the epoch, which is the recommended value to also store timestamps in Firebase.
The 1622790000000 value in the rules is the timestamp of some point in the future. Let's see what this value is in a more readable date format:
console.log(new Date(1622790000000))
"2021-06-04T07:00:00.000Z"
So anyone can read of write all data in our database until June 4th, 2021. After that date nobody can access the data anymore with the client-side SDKs. The Firebase Admin SDKs bypass these rules altogether, so they are not affected.
Can I extend the time period?
You may have gotten a message like this from Firebase:
You chose to start developing in Test Mode, which leaves your Realtime Database instance completely open to the Internet. Because this choice makes your app vulnerable to attackers, your database security rules were configured to stop allowing requests after the first 30 days. In 5 day(s), all client requests to your Realtime Database instance will be denied.
This message means that access to your data is about to expire, due to timestamp that is in your security rules.
It's actually pretty easy to extend the test mode to another deadline. All you need to do is change that 1622790000000 value. For example, for extend it to July 4th, I can set the value to 1625382000000.
To determine the value to use, I run this tiny JavaScript snippet:
console.log(new Date("2021-07-04T07:00:00.000Z").getTime())
Run this snippet to get the timestamp exactly one month from now:
console.log(new Date(Date.now()+30*24*60*60*1000).getTime())
Here's another tool to calculate these values.
By using 1625382000000 we've extended test mode for a month and everyone can read/write the entire database until July 4, 2021.
How can I better protect the data?
At some point you should come up with a better way to protect your (user's) data than just opening it until a specific date. I typically do this right when I start a project, but it's also fine if you start it a bit later.
The important thing is that you should treat the server-side security rules the same as the client-side source code of your app.
I develop my code and rules in tandem. So:
I start with a fully closed off database, since there is no code yet that needs access to any data.
I add some data manually to the database, and write code to read it. At this point, I write security rules that only allow read-access to that specific data. So it may be ".read": true, but it'll be much deeper in my JSON structure. Even such simple rules will already block many bad actors.
The first time I want the app to write to the database is also when I add authentication. Typically I start with anonymous auth, since it does not require me to enter any credentials.
I then include the hard-coded UID in my security rules, to ensure only I can write data. You'll often still find this top-level ".write": "auth.uid === 'hardcodedUidOfPufsAnonymousUser'" in my rules much later, after I added proper data ownership.
When using Firestore I sometimes evolve that as explained here: User conflict when using same Auth method for Admin and Normal users | Firebase Auth
At any point when I add (typically lists of) data, I think through who "owns" this data, and who can read it. I then expand my rules to allow exactly that access, and nothing more.
This need to update my security rules as I write code slows down the pace at which I code, but I'll gladly do it anyway. Keeping the data in my database secure at every step, allows me to give people access to the app/database with confidence. I recommend you do the same.
For more information, I recommend reading:
The Firebase documentation on security rules, which contains examples of these common use-cases:
Content-owner only access
Public read, private write access
Attribute and role based access
All authenticated users can read/write all datsa
{
"rules": {
".read": "true",
".write": "true",
}
}
Even after updating my rules with this, still I'm receiving warnings that I should update my firebase realtime database and also, I have also received that if I have modified rules in last 24 hours, those changes are not accounted for, what do I do now?
The rules in your question allow anyone in the world to read and write whatever they want in your database. If they know the URL of your database, they can steal and/or wipe all of your data with a single call.
That's what the Firebase email is warning you about. I highly recommend studying it carefully, and then following up with:
the Firebase documentation on its server-side security rules
the Realtime Database specific documentation for the rules, including the video in there
Firebase email saying my realtime database has insecure rules
Swift 3.0 iOS 11.x
So link my swift app to a firebase using the standard
FirebaseApp.configure()
I log into it with a user I have created, authentication registers good and I create a database on it. All good.
I take a different device and try log in with a user who doesn't exist, authentication fails and I am unable to access the database. All good.
But wait, I create another user; and given I know the path of the database I find I have access to it. Which would seem reasonable, and yet it isn't.
Imagine I have 10 different app users, they all have their own databases; and yet as long as they are authenticating to firebase, they potentially mess each other up since everyone seem to have access to everyone else's database as long as they have authenticated. Indeed I look at this post...
How to link between Authenticated users and Database in Firebase? which seems to suggest things are a little tighter, and yet evidently their not.
I'v missed something fundamental here haven't I?
This is secured through Firebase Rules. You can check out the documentation for full detailed information about the topic.
The structure you are looking for would look something like this:
{
rules: {
$uid: {
".read" = "auth.uid == $uid",
".write" = "auth.uid == $uid"
}
}
}
You have to be careful with this one because this does not apply to every database structure. This one would work, if you create a node for every user in the root of your database and specify the users authentication id as the key. A user could only access the data in the node with his Firebase Authentication id, although in that node all data, also every child node of it.
Check out the docs for more information. You can find your rules in the Firebase Console in the Database tab.
So this question is more about the proper way to use Firebase and store data. The user will be given the chance to post (remember not server POST) to other users in the area something that they will read, much like craigslist. I am using Firebase and am unsure oh how to save this information. There will be both a title portion that will be no more then a sentence and then a description portion that I wouldn't want to be outrageously long but still have some depth so the user can take advantage of that.
should it be in the database with a key, but if so the documentation tells me that I can't use .(periods)? (btw how much text would 10mb be?)
Should it be in storage and saved as a .txt file that I would then have all the users pull up whenever they check the "post feed" for their area?
I am currently using Facebook authentication and saving their information into the database (except their profile picture which goes into storage).
This is all being done in swift and the newest Firebase with GeoFire as will. Any and all explicit code examples will be helpful as I am still learning. Thank you so much!
First of all, you should use the real-time database and not the storage service for this type of app.
Use the storage for saving things like photos, videos or attachments.
As for how to store these "posts" IU n the db, you don't need to worry about special characters since firebase doesn't allow them in the "keys" or node names but you can definitely use them in the values, for example:
"Posts": {
"some_unique_id_for_post_1" : {
"Title": "post 1's title",
"Body": "post 1's text body"
}
}
It can get a bit tricky if you try to implement social network type of functionality like "likes", "comments" and "followers" so this might help:
https://medium.com/#gilg/from-sql-to-firebase-how-to-structure-the-db-for-a-social-network-app-95b0aa5664c0?source=linkShare-af537a57f12f-1470401682