避免不安全的规则

请阅读本指南,了解 Firebase Security Rules配置中的常见漏洞,检查并更好地保护您自己的规则,并在部署之前先测试更改。

如果您收到有关数据未得到适当保护的提醒,请查看这些常见错误并更新所有易受攻击的规则。

访问您的 Firebase Security Rules

如需查看现有的 Rules,请使用 Firebase CLI 或 Firebase 控制台。确保始终使用同一方法修改您的规则,以避免错误地覆盖更新。如果您不能确定本地定义的规则是否反映了最近的更新,Firebase 控制台中会始终显示最近部署的 Firebase Security Rules 版本。

如需从 Firebase 控制台访问您的规则,请选择您的项目,然后前往 Realtime DatabaseCloud FirestoreStorage。您进入正确的数据库或存储分区之后,请点击规则

如需从 Firebase CLI 访问您的规则,请打开 firebase.json 文件中记录的规则文件。

了解 Firebase Security Rules

Firebase Security Rules可保护您的数据免受恶意用户的攻击。在 Firebase 控制台中创建数据库实例或 Cloud Storage 存储分区时,您可以选择拒绝所有用户的访问权限(锁定模式),或者为所有用户授予访问权限(测试模式)。虽然您可能想要在开发期间采用更加开放的配置,但是在部署应用之前,确保花些时间正确配置规则并保护数据。

在开发应用和测试规则的不同配置时,请使用本地 Firebase 模拟器在本地开发环境中运行您的应用。

具有不安全规则的常见场景

您可能已经设置了默认的 Rules,或者在刚开始开发应用时设置了规则,但在部署应用之前,您应该检查并更新这些规则。确保避免以下常见误区,从而妥善保护用户数据的安全。

允许所有人访问

在开发期间,您在设置 Firebase 项目时可能已将您的规则设置为允许所有人访问。您可能认为只有您在使用自己的应用,但如果您已经部署了该应用,互联网用户就都可以使用。如果您未对用户进行身份验证并配置安全规则,猜测出您的项目 ID 的任何人都可以窃取、篡改或删除数据。

不推荐:为所有用户提供读写权限。
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this ruleset in production; it allows
// anyone to overwrite your entire database.

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
{
  // Allow read/write access to all users under any conditions
  // Warning: **NEVER** use this ruleset in production; it allows
  // anyone to overwrite your entire database.

  "rules": {
    ".read": true,
    ".write": true
  }
}
    
// Anyone can read or write to the bucket, even non-users of your app.
// Because it is shared with App Engine, this will also make
// files uploaded using App Engine public.
// Warning: This rule makes every file in your Cloud Storage bucket accessible to any user.
// Apply caution before using it in production, since it means anyone
// can overwrite all your files.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write;
    }
  }
}
    
解决方法:使用规则限制读写权限。

构建适合您的数据层次结构的规则。针对这种危险因素的一种常见解决方案是,使用 Firebase Authentication 实现基于用户的安全控制。详细了解如何使用规则对用户进行身份验证

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow only authenticated content owners access
    match /some_collection/{document} {
      // Allow reads and deletion if the current user owns the existing document
      allow read, delete: if request.auth.uid == resource.data.author_uid;
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;

    }
  }
}
  
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      // Allow public reads
      allow read: if true
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;
      // Allow deletion if the current user owns the existing document
      allow delete: if request.auth.uid == resource.data.author_uid;
    }
  }
}
  
{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid"
      }
    }
  }
}
    
{
  // Allow anyone to read data, but only authenticated content owners can
  // make changes to their data

  "rules": {
    "some_path/$uid": {
      ".read": true,
      // or ".read": "auth.uid !== null" for only authenticated users
      ".write": "auth.uid === $uid"
    }
  }
}
    
// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}
  

为通过身份验证的用户提供访问权限

有时,Rules会检查用户是否已登录,但不会再通过身份验证进一步限制访问权限。如果您的某一条规则包含 auth != null,请确认您是否想让所有已登录的用户有权访问数据。

不推荐:任何登录用户都有权在您的整个数据库中读写数据。
service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow read, write: if request.auth.uid != null;
    }
  }
}
{
  "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}
// Only authenticated users can read or write to the bucket
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}
解决方案:使用安全条件缩小访问权限范围。

在验证身份时,您可以使用某个身份验证属性来进一步限制特定用户对特定数据集的访问权限。详细了解不同的身份验证属性

service cloud.firestore {
  match /databases/{database}/documents {
    // Assign roles to all users and refine access based on user roles
    match /some_collection/{document} {
     allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader"
     allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"

     // Note: Checking for roles in your database using `get` (as in the code
     // above) or `exists` carry standard charges for read operations.
    }
  }
}
// Give each user in your database a particular attribute
// and set it to true/false
// Then, use that attribute to grant access to subsets of data
// For example, an "administrator" attribute set
// to "true" grants write access to data

service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
      allow read: true;
    }
  }
}
  
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      allow read: if true
      allow write: if request.auth.uid == request.resource.data.author_uid
    }
  }
}
  
{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth.uid === $uid",
        ".write": "auth.uid === $uid"
      }
    }
  }
}
    
{
  "rules": {
    "some_path/$uid": {
      ".write": "auth.uid === $uid",
      // Create a "public" subpath in your dataset
      "public": {
        ".read": true
        // or ".read": "auth.uid !== null"
      },
      // Create a "private" subpath in your dataset
      "private": {
        ".read": "auth.uid === $uid"
      }
    }
  }
}
    
{
  // Allow anyone to read data, but only authenticated content owners can
  // make changes to their data

  "rules": {
    "some_path/$uid": {
      ".read": true,
      // or ".read": "auth.uid !== null" for only authenticated users
      ".write": "auth.uid === $uid"
    }
  }
}
    
// Allow reads if the group ID in your token matches the file metadata `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}
// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}
  

(Realtime Database) 不当继承的规则

Realtime Database Security Rules 会进行级联,即用较浅层的父路径上的规则替换较深层的子节点上的规则。在子节点上编写规则时,请注意它只能授予额外的特权。您无法在数据库的较深层路径中细化或撤消数据访问权限。

不推荐:在子路径上细化规则
{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}
解决方案:在宽泛的父路径中编写规则,并在子路径授予更具体的特权 如果您需要更具体地控制数据访问权限,请提供细化规则。 如需详细了解如何级联 Realtime Database Security Rules,请参阅 Realtime Database Security Rules 的核心语法

关闭访问权限

在开发应用时,另一种常见方法是封锁数据。通常,这意味着您已关闭所有用户的读写权限,如下所示:

// Deny read/write access to all users under any conditions
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
{
  "rules": {
    ".read": false,
    ".write": false
  }
}
    
// Access to files through Cloud Storage is completely disallowed.
// Files may still be accessible through App Engine or Google Cloud Storage APIs.

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

Firebase Admin SDK 和 Cloud Functions 仍可以访问您的数据库。如果您打算将 Cloud FirestoreRealtime Database 作为仅限服务器的后端与 Firebase Admin SDK 结合使用,请使用这些规则。虽然这种做法是安全的,但您应该测试应用的客户端是否可以正确检索数据。

如需详细了解 Cloud Firestore Security Rules 及其工作原理,请参阅 Cloud Firestore Security Rules使用入门

测试您的 Cloud Firestore Security Rules

如需检查应用的行为并验证您的 Cloud Firestore Security Rules 配置,请使用 Firebase 模拟器。先使用 Cloud Firestore 模拟器在本地环境中运行单元测试并使之自动化,然后再部署更改。

如需在 Firebase 控制台中快速验证 Firebase Security Rules,请使用 Firebase 规则模拟器