Избегайте небезопасных правил

Используйте это руководство, чтобы понять распространенные уязвимости в конфигурациях Firebase Security Rules , просмотреть и лучше защитить свои собственные правила, а также протестировать изменения перед их развертыванием.

Если вы получили предупреждение о том, что ваши данные не защищены должным образом, просмотрите эти распространенные ошибки и обновите все уязвимые правила.

Получите доступ к своим Firebase Security Rules

Чтобы просмотреть существующие Rules , используйте интерфейс командной строки Firebase или консоль Firebase . Обязательно редактируйте свои правила, используя один и тот же метод, последовательно, чтобы избежать ошибочной перезаписи обновлений. Если вы не уверены, отражают ли ваши локально определенные правила самые последние обновления, консоль Firebase всегда показывает самую последнюю развернутую версию ваших Firebase Security Rules .

Чтобы получить доступ к своим правилам из консоли Firebase , выберите свой проект, затем перейдите к Realtime Database , Cloud Firestore или хранилищу . Нажмите «Правила» , как только вы окажетесь в нужной базе данных или сегменте хранилища.

Чтобы получить доступ к своим правилам из интерфейса командной строки Firebase , перейдите к файлу правил, указанному в файле firebase.json .

Понимание Firebase Security Rules

Firebase Security Rules защищают ваши данные от злоумышленников. Когда вы создаете экземпляр базы данных или корзину Cloud Storage в консоли Firebase , вы можете либо запретить доступ всем пользователям ( режим блокировки ), либо предоставить доступ всем пользователям ( режим тестирования ). Хотя во время разработки вам может потребоваться более открытая конфигурация, убедитесь, что вы нашли время правильно настроить правила и защитить свои данные перед развертыванием приложения.

Разрабатывая приложение и тестируя различные конфигурации правил, используйте один из локальных эмуляторов Firebase, чтобы запустить приложение в локальной среде разработки.

Распространенные сценарии с небезопасными правилами

Rules вы, возможно, установили по умолчанию или изначально работали над разработкой приложения, следует просмотреть и обновить перед развертыванием приложения. Убедитесь, что вы правильно защищаете данные своих пользователей, избегая следующих распространенных ошибок.

Открытый доступ

При настройке проекта Firebase вы, возможно, установили правила, разрешающие открытый доступ во время разработки. Вы можете подумать, что вы единственный, кто использует ваше приложение, но если вы его развернули, оно будет доступно в Интернете. Если вы не выполняете аутентификацию пользователей и не настраиваете правила безопасности, любой, кто угадает идентификатор вашего проекта, сможет украсть, изменить или удалить данные.

Не рекомендуется: доступ для чтения и записи для всех пользователей.
// 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;
    }
  }
}

SDK администратора Firebase и облачные функции по-прежнему смогут получить доступ к вашей базе данных. Используйте эти правила, если вы собираетесь использовать Cloud Firestore или Realtime Database в качестве серверной части в сочетании с Firebase Admin SDK. Несмотря на то, что это безопасно, вам следует проверить, могут ли клиенты вашего приложения правильно получать данные.

Узнайте больше о Cloud Firestore Security Rules и о том, как они работают, в разделе «Начало работы с Cloud Firestore Security Rules .

Проверьте свои Cloud Firestore Security Rules

Чтобы проверить поведение вашего приложения и проверить настройки Cloud Firestore Security Rules , используйте эмулятор Firebase . Используйте эмулятор Cloud Firestore для запуска и автоматизации модульных тестов в локальной среде перед развертыванием каких-либо изменений.

Чтобы быстро проверить Firebase Security Rules в консоли Firebase , используйте симулятор правил Firebase .