You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Firebase Storage文件夹权限安全:多页面多用户视频上传防护

How to Secure Firebase Storage Folders from Unauthorized Access via Client-Side URL Manipulation

Great question—this is a common security pitfall when dealing with client-side uploads to Firebase Storage. The core issue here is that you can't trust any path or input generated directly on the client; you need to enforce access controls at the server level and lock down how upload paths are created. Here's a step-by-step solution:

1. Enforce Access with Firebase Storage Security Rules

The first line of defense is Firebase's built-in security rules. These rules run directly on Firebase's servers, so they can't be bypassed by client-side tampering. You'll want to tie access to the user's authenticated UID (unique, unchangeable identifier from Firebase Auth) to ensure users only access their own folders.

Example Security Rules:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    // Allow read/write access ONLY to the user's own folder
    match /resource/video/{userId}/{allPaths=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }

    // Block all access to any other folders
    match /{otherPaths=**} {
      allow read, write: if false;
    }
  }
}
  • Why this works: The rule checks that the userId segment in the storage path matches the authenticated user's UID. Even if a user modifies the URL to point to someone else's folder, Firebase will reject the request immediately.
  • Pro tip: Use the user's UID instead of a username—usernames can be changed or duplicated, but UIDs are permanent and unique per user.

2. Generate Upload Paths Safely on the Client

Don't let users control any part of the upload path. Instead, auto-generate the path using trusted data (like the user's UID and page-specific identifiers) that the client can't tamper with.

Modified Client-Side Code:

// Ensure the user is authenticated before allowing uploads
firebase.auth().onAuthStateChanged(user => {
  if (user) {
    const userId = user.uid; // Get the user's secure, permanent UID
    const pageSpecificPath = getPageFolder(); // Auto-detect the folder for the current page
    
    // Build the upload path without any user-editable parts
    const uploadPath = `resource/video/${userId}/${pageSpecificPath}/mountains.mp4`;
    const storageRef = firebase.storage().ref();
    const uploadTask = storageRef.child(uploadPath).put(file, metadata);
  } else {
    alert("Please log in to upload videos.");
  }
});

// Helper function to get the correct folder based on the current page
function getPageFolder() {
  // Use the current page's URL or a hardcoded identifier to pick the folder
  const currentPage = window.location.pathname;
  if (currentPage.includes("/upload-page-1")) {
    return "project1/blabla/blabla";
  } else if (currentPage.includes("/upload-page-2")) {
    return "project2/blabla/blabla";
  }
  // Add cases for your other 4 pages here
}
  • Why this works: The path is built using data that's either tied to the authenticated user (UID) or auto-detected from the page context. There's no way for the user to modify these values without altering the page's code (which would be obvious and easy to detect).

3. (Optional) Use Cloud Functions for Advanced Permissions

If you need to enforce more complex rules (like restricting certain users from uploading to specific page folders), use Firebase Cloud Functions as an upload middleman. This way, the client never interacts directly with Storage—all uploads go through the function, which validates permissions first.

Example Cloud Function (Node.js):

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const { Storage } = require("@google-cloud/storage");
const storage = new Storage();

exports.secureVideoUpload = functions.https.onCall(async (data, context) => {
  // Reject unauthenticated requests
  if (!context.auth) {
    throw new functions.https.HttpsError("unauthenticated", "Please log in first.");
  }

  const userId = context.auth.uid;
  const { file, pageKey } = data; // Page key passed from the client (e.g., "page1")

  // Check if the user has permission to upload to this page's folder
  const userPermissions = await admin.firestore()
    .collection("userPermissions")
    .doc(userId)
    .get();
  
  if (!userPermissions.exists || !userPermissions.data().allowedPages.includes(pageKey)) {
    throw new functions.https.HttpsError("permission-denied", "You don't have access to this upload page.");
  }

  // Map page keys to storage folders
  const pageFolders = {
    page1: "project1/blabla/blabla",
    page2: "project2/blabla/blabla"
    // Add other pages here
  };

  // Upload the file to the correct, secure path
  const bucket = storage.bucket(admin.storage().bucket().name);
  const targetPath = `resource/video/${userId}/${pageFolders[pageKey]}/mountains.mp4`;
  const fileRef = bucket.file(targetPath);
  await fileRef.save(file, { contentType: "video/mp4" });

  // Return a signed download URL (optional)
  const [downloadUrl] = await fileRef.getSignedUrl({
    action: "read",
    expires: "03-01-2500"
  });
  return { downloadUrl };
});
  • Client-side call:
    firebase.auth().onAuthStateChanged(user => {
      if (user) {
        const uploadFunction = firebase.functions().httpsCallable("secureVideoUpload");
        uploadFunction({
          file: file,
          pageKey: "page1" // Match this to the current page
        }).then(result => {
          console.log("Upload successful!", result.data.downloadUrl);
        }).catch(error => {
          console.error("Upload failed:", error.message);
        });
      }
    });
    
  • Why this works: All permission checks happen on Firebase's servers, so even if a user modifies the client code to send a fake pageKey, the function will reject the request.

Final Notes

  • Always prioritize Firebase Security Rules as your base layer—they're lightweight and designed specifically for this use case.
  • Never expose sensitive path segments (like user IDs or project IDs) in a way that users can edit. Auto-generate all critical parts of the path.
  • For complex permission scenarios, Cloud Functions give you full control over who can upload where.

内容的提问来源于stack exchange,提问作者Alican Kablan

火山引擎 最新活动