0

I'm working on a PoC (Proof of Concept) application that users can download wallpapers to their device. All of the data is served using Cloud Firestore & Storage.

There is NO LOGIN for this application. Anybody can download the application, and immediately download the wallpapers she or he desires.

Bearing that in mind... I would like to have a counter that tracks how many times each specific wallpaper was downloaded.

While I have it "working" - I am questioning the rules I have set up in Firebase..

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read;
      allow write: if request.auth != null;
      allow update: if request.resource.data.counter is number;
    }
  }
}

My thought process with the rules above:

  • Anybody can read.
  • Only authenticated users can write. (I am managing all of the data with a headless CMS; Flamelink; so the 1 and only authenticated user is myself.)
  • Update the counter if the data is a number..

It's that last rule that I am questioning.

Is this a safe method of security to deploy to production?

Again - no login for this application, users can download all of the wallpapers with no authentication, and there will be a counter next to each wallpaper for users to see how many times each wallpaper has been downloaded.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
Joe
  • 3,772
  • 3
  • 33
  • 64
  • It's safe only if it meets the needs of your app. We can't really tell what those needs are given when you've expressed here. What is the problem you're trying to prevent? – Doug Stevenson Feb 17 '20 at 06:31
  • 1
    I am not sure why the accepted answer was accepted. Your question clearly states *Update the counter if the data is a number..* which means data is written (inserted) into your Firebase. That answer assumes *no data will be inserted on your system*. Additionally your question states *Is this a safe method of security to deploy to production?* and the answer is that the rules won't work for the use case described in the question as when a wallpaper is downloaded the counter would need to be incremented which would require a write, and a write can only be performed by an authenticated user. – Jay Feb 19 '20 at 19:21
  • @Jay - I took the accepted answers context "no data will be inserted on your system" as true, because I am the only one authoring _new_ data. When a new wallpaper gets added to Firebase (to display on the App), the counter defaults to 0. By using the following line, I am (or my assumptions are...) only letting the public UPDATE that counter: `allow update: if request.resource.data.counter is number;`. Is my assumption false here? And if so, what rules would you recommend, bearing in mind there is no login, and all I am trying to accomplish is updating a download counter? – Joe Feb 19 '20 at 19:47
  • 1
    Understood. My thinking/question was that *Only authenticated users can write* was in conflict with the app updating a counter because if the app can update the counter without being authenticated then anyone can e.g. i could craft a quick app to increment that counter to 1,000,000 which would not be good security/safe. Perhaps I am not understanding the use case. – Jay Feb 19 '20 at 20:39
  • @Jay - Appreciate the follow-up. My use is anybody that downloads the App is able to view/download wallpapers for free. There is no login whatsoever. Every time the user downloads a wallpaper, the counter increments. Since this is utilizing cloud firestore, the counter increments in real-time. I want as much security to protect my data as possible, while still letting the counter increment as intended. Based on this use case, I tried writing the rules as "strict" as possible. Not sure how you'd be able to hijack my counter, but that is quite intriguing! – Joe Feb 19 '20 at 21:37
  • The counter can be hijacked by using the public REST API for Firestore along with a known Firebase auth ID token. This can be culled from the device (or simply using the Firebase Auth REST API if you allow email/password auth), and the attacker can use it to write maliciously to ANY document(s) in your database. Your rules are unnecessarily permissive on this front (do you really want any document to be modified by anyone?). IMO, you should unaccept the answer and be more specific about what you consider to be "secure" access. What you have now does not sound "secure" as @Jay suggests. – Doug Stevenson Feb 20 '20 at 08:12
  • As a brief followup, the rules you have right now let me, without authentication, (if I know the name of your project, which will be baked into your public app), allows me to query for *all* of the documents in your app if I know the name of the collection (also baked into your app), and allows me to update the `counter` field of any one of them. Is that what you want? – Doug Stevenson Feb 20 '20 at 08:23
  • I wrote a (very) long answer and forgot to post. Fortunately @DougStevenson summed it up with far fewer words. lol. In a nutshell, I can read your entire structure. I can then drill down to any particular wallpaper, locate the node that stores the download count and set it to whatever number I want. The only thing that's required is I know your url, which can be derived from your app. That's not secure IMO. – Jay Feb 20 '20 at 14:59

1 Answers1

1

The rules are not "secure" by any normal definition of that word. Here's what they allow. Anyone with an internet connection who knows the name of the project (which is easy to get) can:

  • Query for any document in the database
  • Update any existing document with any numeric value for counter in any document (it doesn't even have to increment, or be a positive integer)

On top of that, anyone who is able to get their Firebase Auth ID token (again, not terribly difficult for determined attacker), can fully create and write any document in the database. If you say there is no Auth at all in your app, then this is not really an issue, but if your project is configured to allow any form of authentication, it would be possible for an attacker to start writing anything.

You will get email from Firebase saying that your rules are not secure, mostly because you're allowing everyone to read everything.

What you should do is define more specifically what your security requirements are, then translate those into rules that actually meet those requirements. If you want to allow unauthenticated write access to your database of any kind, you are in a bit of trouble, as there is no way to make sure that the access actually matches the download behavior you're trying to measure. You'll be better off counting the downloads in whatever process manages the download, which is probably going to require a more sophisticated backend than what you have now.

But if allowing public read/write access is indeed what you want to allow, you'll be better off by making your rules more specific. For example, you can limit which collection the anonymous user can write to, and making sure they can only ever increment the counter, if these are the things you want.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441