Структурирование правил безопасности Cloud Firestore

Cloud Firestore Security Rules позволяют вам контролировать доступ к документам и коллекциям в вашей базе данных. Гибкий синтаксис правил позволяет создавать правила, соответствующие чему угодно: от всех операций записи во всю базу данных до операций над конкретным документом.

В этом руководстве описываются основной синтаксис и структура правил безопасности. Объедините этот синтаксис с условиями правил безопасности, чтобы создать полные наборы правил.

Декларация службы и базы данных

Cloud Firestore Security Rules всегда начинаются со следующего объявления:

service cloud.firestore {
  match /databases/{database}/documents {
    // ...
  }
}

Объявление service cloud.firestore распространяет правила на Cloud Firestore , предотвращая конфликты между Cloud Firestore Security Rules и правилами для других продуктов, таких как Cloud Storage.

Объявление match /databases/{database}/documents указывает, что правила должны соответствовать любой базе данных Cloud Firestore в проекте. В настоящее время каждый проект имеет только одну базу данных с именем (default) .

Основные правила чтения/записи

Основные правила состоят из оператора match , определяющего путь к документу, и выражения allow , определяющего, когда разрешено чтение указанных данных:

service cloud.firestore {
  match /databases/{database}/documents {

    // Match any document in the 'cities' collection
    match /cities/{city} {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

Все операторы сопоставления должны указывать на документы, а не на коллекции. Оператор match может указывать на конкретный документ, как в match /cities/SF или использовать подстановочные знаки для указания на любой документ по указанному пути, как в match /cities/{city} .

В приведенном выше примере оператор сопоставления использует синтаксис подстановочного знака {city} . Это означает, что правило применяется к любому документу в коллекции cities , например /cities/SF или /cities/NYC . При оценке allow выражений в операторе сопоставления переменная city преобразуется в имя документа города, например SF или NYC .

Детальные операции

В некоторых ситуациях полезно разбить read и write на более детальные операции. Например, вашему приложению может потребоваться применять разные условия при создании документа и при его удалении. Или вы можете разрешить чтение отдельных документов, но запретить большие запросы.

Правило read можно разбить на get и list , а правило write — на create , update и delete :

service cloud.firestore {
  match /databases/{database}/documents {
    // A read rule can be divided into get and list rules
    match /cities/{city} {
      // Applies to single document read requests
      allow get: if <condition>;

      // Applies to queries and collection read requests
      allow list: if <condition>;
    }

    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if <condition>;

      // Applies to writes to existing documents
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
}

Иерархические данные

Данные в Cloud Firestore организованы в коллекции документов, и каждый документ может расширять иерархию за счет подколлекций. Важно понимать, как правила безопасности взаимодействуют с иерархическими данными.

Рассмотрим ситуацию, когда каждый документ в коллекции cities содержит подколлекцию landmarks . Правила безопасности применяются только к соответствующему пути, поэтому элементы управления доступом, определенные в коллекции cities не применяются к подколлекции landmarks . Вместо этого напишите явные правила для управления доступом к подколекциям:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

        // Explicitly define rules for the 'landmarks' subcollection
        match /landmarks/{landmark} {
          allow read, write: if <condition>;
        }
    }
  }
}

При вложении операторов match путь внутреннего match сопоставления всегда находится относительно пути внешнего match сопоставления. Таким образом, следующие наборы правил эквивалентны:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

Рекурсивные подстановочные знаки

Если вы хотите, чтобы правила применялись к произвольно глубокой иерархии, используйте рекурсивный синтаксис подстановочных знаков {name=**} . Например:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

При использовании рекурсивного синтаксиса подстановочных знаков переменная подстановочных знаков будет содержать весь соответствующий сегмент пути, даже если документ расположен в глубоко вложенной подколлекции. Например, перечисленные выше правила будут соответствовать документу, расположенному по адресу /cities/SF/landmarks/coit_tower , а значение переменной document будет SF/landmarks/coit_tower .

Однако обратите внимание, что поведение рекурсивных подстановочных знаков зависит от версии правил.

Версия 1

Правила безопасности по умолчанию используют версию 1. В версии 1 рекурсивные подстановочные знаки соответствуют одному или нескольким элементам пути. Они не соответствуют пустому пути, поэтому match /cities/{city}/{document=**} соответствует документам в подколекциях, но не в коллекции cities , тогда как match /cities/{document=**} соответствует обоим документам в коллекции. Коллекция cities и подколлекции.

Рекурсивные подстановочные знаки должны располагаться в конце оператора сопоставления.

Версия 2

В правилах безопасности версии 2 рекурсивные подстановочные знаки соответствуют нулю или более элементам пути. match/cities/{city}/{document=**} сопоставляет документы во всех подколекциях, а также документы в коллекции cities .

Вы должны подписаться на версию 2, добавив rules_version = '2'; в верхней части правил безопасности:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Вы можете использовать не более одного рекурсивного подстановочного знака для каждого оператора сопоставления, но в версии 2 вы можете разместить этот подстановочный знак в любом месте оператора сопоставления. Например:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

Если вы используете запросы группы сбора , вы должны использовать версию 2, см. раздел «Защита запросов группы сбора» .

Перекрывающиеся операторы сопоставления

Документ может соответствовать более чем одному оператору match . В случае, когда запросу соответствует несколько выражений allow , доступ разрешается, если какое-либо из условий true :

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

В приведенном выше примере все операции чтения и записи в коллекцию cities будут разрешены, поскольку второе правило всегда true , даже если первое правило всегда false .

Ограничения правил безопасности

При работе с правилами безопасности обратите внимание на следующие ограничения:

Лимит Подробности
Максимальное количество вызовов exists() , get() и getAfter() на один запрос
  • 10 для запросов по одному документу и запросов.
  • 20 для чтения нескольких документов, транзакций и пакетной записи. Предыдущее ограничение в 10 также применяется к каждой операции.

    Например, представьте, что вы создаете пакетный запрос на запись с тремя операциями записи и что ваши правила безопасности используют два вызова доступа к документу для проверки каждой записи. В этом случае каждая запись использует 2 из 10 вызовов доступа, а пакетный запрос на запись использует 6 из 20 вызовов доступа.

Превышение любого ограничения приводит к ошибке отказа в разрешении.

Некоторые вызовы доступа к документу могут кэшироваться, и кэшированные вызовы не учитываются при расчете ограничений.

Максимальная глубина вложенного оператора match 10
Максимальная длина пути в сегментах пути, разрешенная в наборе вложенных операторов match . 100
Максимальное количество переменных захвата пути, разрешенное в наборе вложенных операторов match 20
Максимальная глубина вызова функции 20
Максимальное количество аргументов функции 7
Максимальное количество привязок переменных let на функцию 10
Максимальное количество рекурсивных или циклических вызовов функций 0 (не разрешено)
Максимальное количество выражений, оцениваемых за запрос 1000
Максимальный размер набора правил Наборы правил должны подчиняться двум ограничениям по размеру:
  • ограничение в 256 КБ на размер источника текста набора правил, опубликованного из консоли Firebase или из интерфейса командной строки с помощью firebase deploy .
  • ограничение размера скомпилированного набора правил в 250 КБ, которое возникает, когда Firebase обрабатывает источник и делает его активным на серверной стороне.

Следующие шаги