Who can upload files to your Firebase storage bucket? What kind of files can they upload? Do you control the size of those files? What happens if someone uploads an entire movie to your bucket?

Those are all valid questions that you’ve probably asked yourself in the past. Firebase Cloud Storage is great for storing files and assets in the cloud, but to properly use it, we can’t let everyone go ahead and upload anything they want.

In this article, we’re going to go over 3 things:

  • Who gets to upload files on our storage bucket.
  • The kind of files they upload.
  • The size of the files they’ll upload.

With that in mind, let’s begin!

Who gets to upload files

Cloud Storage manages its security in the same way Firestore does, with security rules.

To access them, you go to the Firebase console, click on the Storage tab, and inside, you click on rules, as seen in the image below.

Cloud Storage Security Rules

Since you’re paying for everything that gets uploaded to your storage bucket, I believe there are 3 restrictions you need to enable right away, first, make sure only authenticated users get to upload files:

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Similar to writing Firestore security rules, the biggest change is that Firestore is a Document oriented database where you write your rules based on collections and documents.

Cloud Storage is a big bucket to put files in, so you write the rules for the file paths:

  • match /{allPaths=**} means that the rule applies everywhere in the bucket.
  • match /user/{userId}/ means that the rule matches the documents inside the following path: user/{folder_name}.
  • match /user/{userId}/{allPaths=**} means that the rule matches indie the user/{folder_name} path and all the subfolders inside of it.

How you limit the size of those files

Since you don’t want your users to upload large files, you can also limit the file’s size like this:

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null && request.resource.size < 1024 * 1024;
    }
  }
}

Note that we’re reading the size property of the resource inside of the request, and telling it we won’t allow file larger than 1MB.

The request.resource.size is stored in bytes, so it’s 1024 bytes * 1024 kilobytes = 1MB.

We can also use functions here, to make things more readable, for example:

service firebase.storage {
  match /b/{bucket}/o {
    function restrictFileSize(sizeInMB) {
      return request.resource.size < sizeInMB * 1024 * 1024;
    }

    match /users/{userId}/{allPaths=**} {
      allow read, write: if restrictFileSize(5);
    }
  }
}

Note how we made the restrictFileSize() function dynamic, it will work for different paths, all you need to do is send the file size you want to restrict in Megabytes.

Sadly, we can’t access the .get() property like in Firestore Security Rules, so you need to plan accordingly. What do I mean by this? You need to make sure that the information you need to perform the rule is either in the path or the document’s metadata.

Block file types from being stored in our bucket

One thing you want to make sure of is that people aren’t using your storage bucket to host malicious code.

For example, what happens if I store a javascript file, and then send the download link to people? Whenever they click that link, the JS would execute on their browsers.

To restrict this, one good idea is to tell your security rules the types of files you are going to allow, for example, if you’ll only allow them to store sale receipts in image and PDF format, you can use the security rules to tell the app to only allow pdfs and images.

For that, we can use the request variable, it holds the resource we’re uploading with all its metadata.

Let’s bring all the previous examples together and write security rules that match the next criteria:

  • Only the user owner of the folder can upload files.
  • They will only upload images and PDFs.
  • The file can’t be larger than 5MB.
service firebase.storage {
  match /b/{bucket}/o {
    function isAllowedFile() {
      return request.resource.contentType.matches('image/jpeg')
     || request.resource.contentType.matches('image/png')
     || request.resource.contentType.matches('image/webp')
     || request.resource.contentType.matches('image/tiff')
     || request.resource.contentType.matches('application/pdf')
    }

    function restrictFileSize(sizeInMB) {
      return request.resource.size < sizeInMB * 1024 * 1024;
    }

    function isFolderOwner(userId) {
      return request.auth != null && if request.auth.uid == userId;
    }

    match /users/{userId}/{allPaths=**} {
      allow read, write: if isFolderOwner(userId) && restrictFileSize(5) && isAllowedFile();
    }
  }
}

Note how we’re using the functions to keep the rules more readable.

If you have any questions, do let me know, you can use the Get Support section below or send me an email jorge@jsmobiledev.com 😃