Как работают правила безопасности

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

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

Выберите продукт, чтобы узнать больше о его правилах.

Cloud Firestore

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage используют следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

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

  • Запрос: метод или методы, вызываемые в операторе allow . Это методы, которые вы разрешаете запускать. Стандартные методы: get , list , create , update и delete . Удобные методы read и write обеспечивают широкий доступ для чтения и записи в указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в виде пути URI.
  • Правило: оператор allow , который включает условие, разрешающее запрос, если его значение истинно.

Правила безопасности версии 2

По состоянию на май 2019 года доступна версия 2 правил безопасности Firebase . Версия 2 правил изменяет поведение рекурсивных подстановочных знаков {name=**} . Если вы планируете использовать запросы групп сбора , вам необходимо использовать версию 2. Вы должны согласиться на версию 2, указав rules_version = '2'; первая строка в ваших правилах безопасности:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

Соответствующие пути

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

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

Соответствующие подколлекции

Данные в 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>;
    }
  }
}

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

Документ может соответствовать более чем одному оператору 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.
    match /cities/{document} {
      allow read, write: if true;
    }
  }
}

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

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

Если вы хотите, чтобы правила применялись к произвольно глубокой иерархии, используйте рекурсивный синтаксис подстановочных знаков {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, см. раздел «Защита запросов группы сбора» .

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

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

Лимит Подробности
Максимальное количество вызовов 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 обрабатывает источник и делает его активным на серверной стороне.

Cloud Storage

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage используют следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

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

  • Запрос: метод или методы, вызываемые в операторе allow . Это методы, которые вы разрешаете запускать. Стандартные методы: get , list , create , update и delete . Удобные методы read и write обеспечивают широкий доступ для чтения и записи в указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в виде пути URI.
  • Правило: оператор allow , который включает условие, разрешающее запрос, если его значение истинно.

Соответствующие пути

Cloud Storage Security Rules match путям к файлам, используемым для доступа к файлам в Cloud Storage . Правила могут match точным путям или путям с подстановочными знаками, а также правила могут быть вложенными. Если ни одно правило соответствия не разрешает метод запроса или условие оценивается как false , запрос отклоняется.

Точные совпадения

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

Вложенные совпадения

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

Подстановочные совпадения

Правила также можно использовать для match шаблона с использованием подстановочных знаков. Подстановочный знак — это именованная переменная, которая представляет либо одну строку, например profilePhoto.png , либо несколько сегментов пути, например images/profilePhoto.png .

Подстановочный знак создается путем добавления фигурных скобок вокруг имени подстановочного знака, например {string} . Подстановочный знак для нескольких сегментов можно объявить, добавив =** к имени подстановочного знака, например {path=**} :

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

Если файлу соответствует несколько правил, результатом является OR результата оценок всех правил. То есть, если какое-либо правило, которому соответствует файл, оценивается как true , результат будет true .

В правилах файл «images/profilePhoto.png» можно прочитать, если какое-либо condition или other_condition имеет значение true, в то время как файл «images/users/user:12345/profilePhoto.png» зависит только от результата other_condition .

На подстановочную переменную можно ссылаться из match , указывая имя файла или авторизацию пути:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage Security Rules не каскадируются, и правила оцениваются только в том случае, если путь запроса совпадает с путем с указанными правилами.

Запросить оценку

Загрузки, загрузки, изменения и удаления метаданных оцениваются с помощью request отправленного в Cloud Storage . Переменная request содержит путь, по которому выполняется запрос, время получения запроса и новое значение resource , если запрос представляет собой запись. Также включены заголовки HTTP и состояние аутентификации.

Объект request также содержит уникальный идентификатор пользователя и полезную нагрузку Firebase Authentication в объекте request.auth , который будет объяснен далее в разделе «Аутентификация» документации.

Полный список свойств объекта request доступен ниже:

Свойство Тип Описание
auth карта<строка, строка> Когда пользователь входит в систему, он предоставляет uid , уникальный идентификатор пользователя, и token , карту утверждений JWT Firebase Authentication . В противном случае оно будет null .
params карта<строка, строка> Карта, содержащая параметры запроса.
path путь path представляющий путь, по которому выполняется запрос.
resource карта<строка, строка> Новое значение ресурса, присутствующее только в запросах write .
time временная метка Временная метка, представляющая время на сервере, в которое оценивается запрос.

Оценка ресурсов

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

Firebase Security Rules для Cloud Storage предоставляют метаданные файла в объекте resource , который содержит пары ключ/значение метаданных, отображаемых в объекте Cloud Storage . Эти свойства можно проверять при запросах read или write , чтобы гарантировать целостность данных.

При запросах write (таких как загрузка, обновление и удаление метаданных) в дополнение к объекту resource , который содержит метаданные файла, существующего по пути запроса, у вас также есть возможность использовать объект request.resource , который содержит подмножество метаданных файла, которые будут записаны, если запись разрешена. Вы можете использовать эти два значения, чтобы обеспечить целостность данных или обеспечить соблюдение ограничений приложения, таких как тип или размер файла.

Полный список свойств объекта resource доступен:

Свойство Тип Описание
name нить Полное название объекта
bucket нить Имя сегмента, в котором находится этот объект.
generation интервал Генерация объекта Google Cloud Storage для этого объекта.
metageneration интервал Метагенерация объекта Google Cloud Storage для этого объекта.
size интервал Размер объекта в байтах.
timeCreated временная метка Временная метка, представляющая время создания объекта.
updated временная метка Временная метка, представляющая время последнего обновления объекта.
md5Hash нить Хэш MD5 объекта.
crc32c нить Хэш объекта crc32c.
etag нить Этаг, связанный с этим объектом.
contentDisposition нить Расположение контента, связанное с этим объектом.
contentEncoding нить Кодировка содержимого, связанная с этим объектом.
contentLanguage нить Язык контента, связанный с этим объектом.
contentType нить Тип контента, связанный с этим объектом.
metadata карта<строка, строка> Пары ключ/значение дополнительных пользовательских метаданных, указанных разработчиком.

request.resource содержит все это, за исключением generation , metageneration , etag , timeCreated и updated .

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

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

Лимит Подробности
Максимальное количество вызовов firestore.exists() и firestore.get() на один запрос

2 для запросов одного документа и запросов запросов.

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

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

Полный пример

Собрав все это вместе, вы можете создать полный пример правил для решения для хранения изображений:

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) Filename (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow read;
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

Realtime Database

Базовая структура

В Realtime Database Firebase Security Rules состоят из выражений, подобных JavaScript, содержащихся в документе JSON.

Они используют следующий синтаксис:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

В правиле есть три основных элемента:

  • Путь: расположение базы данных. Это отражает структуру JSON вашей базы данных.
  • Запрос: это методы, которые правило использует для предоставления доступа. Правила read и write предоставляют широкий доступ для чтения и записи, а правила validate действуют как вторичная проверка для предоставления доступа на основе входящих или существующих данных.
  • Условие: условие, которое разрешает запрос, если его значение истинно.

Как правила применяются к путям

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

Учитывайте следующие правила:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

Эта структура безопасности позволяет читать /bar/ всякий раз, когда /foo/ содержит дочерний baz со значением true . Правило ".read": false в /foo/bar/ здесь не действует, поскольку доступ не может быть отозван по дочернему пути.

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

Однако правила .validate не каскадируются. Чтобы запись была разрешена, все правила проверки должны соблюдаться на всех уровнях иерархии.

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

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Без понимания того, что правила оцениваются атомарно, может показаться, что выборка пути /records/ вернет rec1 , но не rec2 . Фактический результат, однако, является ошибкой:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Цель-C
Примечание. Этот продукт Firebase недоступен для цели App Clip.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Быстрый
Примечание. Этот продукт Firebase недоступен для цели App Clip.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Поскольку операция чтения в /records/ является атомарной и не существует правила чтения, предоставляющего доступ ко всем данным в /records/ , это приведет к ошибке PERMISSION_DENIED . Если мы оценим это правило в симуляторе безопасности в нашей консоли Firebase , мы увидим, что операция чтения была отклонена:

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

В операции было отказано, поскольку ни одно правило чтения не разрешало доступ к пути /records/ , но учтите, что правило для rec1 никогда не оценивалось, поскольку оно не входило в запрошенный нами путь. Чтобы получить rec1 , нам нужно будет получить к нему прямой доступ:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Цель-C
Примечание. Этот продукт Firebase недоступен для цели App Clip.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Быстрый
Примечание. Этот продукт Firebase недоступен для цели App Clip.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Переменная местоположения

Rules Realtime Database поддерживают переменную $location для сопоставления сегментов пути. Используйте префикс $ перед сегментом пути, чтобы сопоставить правило с любыми дочерними узлами на пути.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

Вы также можете использовать $variable параллельно с именами констант.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

,

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

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

Выберите продукт, чтобы узнать больше о его правилах.

Cloud Firestore

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage используют следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

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

  • Запрос: метод или методы, вызываемые в операторе allow . Это методы, которые вы разрешаете запускать. Стандартные методы: get , list , create , update и delete . Удобные методы read и write обеспечивают широкий доступ для чтения и записи в указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в виде пути URI.
  • Правило: оператор allow , который включает условие, разрешающее запрос, если его значение истинно.

Правила безопасности версии 2

По состоянию на май 2019 года доступна версия 2 правил безопасности Firebase . Версия 2 правил изменяет поведение рекурсивных подстановочных знаков {name=**} . Если вы планируете использовать запросы групп сбора , вам необходимо использовать версию 2. Вы должны согласиться на версию 2, указав rules_version = '2'; первая строка в ваших правилах безопасности:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

Соответствующие пути

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

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

Соответствующие подколлекции

Данные в 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>;
    }
  }
}

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

Документ может соответствовать более чем одному оператору 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.
    match /cities/{document} {
      allow read, write: if true;
    }
  }
}

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

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

Если вы хотите, чтобы правила применялись к произвольно глубокой иерархии, используйте рекурсивный синтаксис подстановочных знаков {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, см. раздел «Защита запросов группы сбора» .

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

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

Лимит Подробности
Максимальное количество вызовов 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 обрабатывает источник и делает его активным на серверной стороне.

Cloud Storage

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage используют следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

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

  • Запрос: метод или методы, вызываемые в операторе allow . Это методы, которые вы разрешаете запускать. Стандартные методы: get , list , create , update и delete . Удобные методы read и write обеспечивают широкий доступ для чтения и записи в указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в виде пути URI.
  • Правило: оператор allow , который включает условие, разрешающее запрос, если его значение истинно.

Соответствующие пути

Cloud Storage Security Rules match путям к файлам, используемым для доступа к файлам в Cloud Storage . Правила могут match точным путям или путям с подстановочными знаками, а также правила могут быть вложенными. Если ни одно правило соответствия не разрешает метод запроса или условие оценивается как false , запрос отклоняется.

Точные совпадения

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

Вложенные совпадения

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

Подстановочные совпадения

Правила также можно использовать для match шаблона с использованием подстановочных знаков. Подстановочный знак — это именованная переменная, которая представляет либо одну строку, например profilePhoto.png , либо несколько сегментов пути, например images/profilePhoto.png .

Подстановочный знак создается путем добавления фигурных скобок вокруг имени подстановочного знака, например {string} . Подстановочный знак для нескольких сегментов можно объявить, добавив =** к имени подстановочного знака, например {path=**} :

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

Если файлу соответствует несколько правил, результатом является OR результата оценок всех правил. То есть, если какое-либо правило, которому соответствует файл, оценивается как true , результат будет true .

В правилах файл «images/profilePhoto.png» можно прочитать, если какое-либо condition или other_condition имеет значение true, в то время как файл «images/users/user:12345/profilePhoto.png» зависит только от результата other_condition .

На подстановочную переменную можно ссылаться из match , указывая имя файла или авторизацию пути:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage Security Rules не каскадируются, и правила оцениваются только в том случае, если путь запроса совпадает с путем с указанными правилами.

Запросить оценку

Загрузки, загрузки, изменения и удаления метаданных оцениваются с помощью request отправленного в Cloud Storage . Переменная request содержит путь, по которому выполняется запрос, время получения запроса и новое значение resource , если запрос представляет собой запись. Также включены заголовки HTTP и состояние аутентификации.

Объект request также содержит уникальный идентификатор пользователя и полезную нагрузку Firebase Authentication в объекте request.auth , который будет объяснен далее в разделе «Аутентификация» документации.

Полный список свойств объекта request доступен ниже:

Свойство Тип Описание
auth карта<строка, строка> Когда пользователь входит в систему, он предоставляет uid , уникальный идентификатор пользователя, и token , карту утверждений JWT Firebase Authentication . В противном случае оно будет null .
params карта<строка, строка> Карта, содержащая параметры запроса.
path путь path представляющий путь, по которому выполняется запрос.
resource карта<строка, строка> Новое значение ресурса, присутствующее только в запросах write .
time временная метка Временная метка, представляющая время на сервере, в которое оценивается запрос.

Оценка ресурсов

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

Firebase Security Rules для Cloud Storage предоставляют метаданные файла в объекте resource , который содержит пары ключ/значение метаданных, отображаемых в объекте Cloud Storage . Эти свойства можно проверять при запросах read или write , чтобы гарантировать целостность данных.

При запросах write (таких как загрузка, обновление и удаление метаданных) в дополнение к объекту resource , который содержит метаданные файла, существующего по пути запроса, у вас также есть возможность использовать объект request.resource , который содержит подмножество метаданных файла, которые будут записаны, если запись разрешена. Вы можете использовать эти два значения, чтобы обеспечить целостность данных или обеспечить соблюдение ограничений приложения, таких как тип или размер файла.

Полный список свойств объекта resource доступен:

Свойство Тип Описание
name нить Полное название объекта
bucket нить Имя сегмента, в котором находится этот объект.
generation интервал Генерация объекта Google Cloud Storage для этого объекта.
metageneration интервал Метагенерация объекта Google Cloud Storage для этого объекта.
size интервал Размер объекта в байтах.
timeCreated временная метка Временная метка, представляющая время создания объекта.
updated временная метка Временная метка, представляющая время последнего обновления объекта.
md5Hash нить Хэш MD5 объекта.
crc32c нить Хэш объекта crc32c.
etag нить Этаг, связанный с этим объектом.
contentDisposition нить Расположение контента, связанное с этим объектом.
contentEncoding нить Кодировка содержимого, связанная с этим объектом.
contentLanguage нить Язык контента, связанный с этим объектом.
contentType нить Тип контента, связанный с этим объектом.
metadata карта<строка, строка> Пары ключ/значение дополнительных пользовательских метаданных, указанных разработчиком.

request.resource содержит все это, за исключением generation , metageneration , etag , timeCreated и updated .

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

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

Лимит Подробности
Максимальное количество вызовов firestore.exists() и firestore.get() на один запрос

2 для запросов одного документа и запросов запросов.

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

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

Полный пример

Собрав все это вместе, вы можете создать полный пример правил для решения для хранения изображений:

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) Filename (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow read;
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

Realtime Database

Базовая структура

В Realtime Database Firebase Security Rules состоят из выражений, подобных JavaScript, содержащихся в документе JSON.

Они используют следующий синтаксис:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

В правиле есть три основных элемента:

  • Путь: расположение базы данных. Это отражает структуру JSON вашей базы данных.
  • Запрос: это методы, которые правило использует для предоставления доступа. Правила read и write предоставляют широкий доступ для чтения и записи, а правила validate действуют как вторичная проверка для предоставления доступа на основе входящих или существующих данных.
  • Условие: условие, которое разрешает запрос, если его значение истинно.

Как правила применяются к путям

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

Учитывайте следующие правила:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

Эта структура безопасности позволяет читать /bar/ всякий раз, когда /foo/ содержит дочерний baz со значением true . Правило ".read": false в /foo/bar/ здесь не действует, поскольку доступ не может быть отозван по дочернему пути.

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

Однако правила .validate не каскадируются. Чтобы запись была разрешена, все правила проверки должны соблюдаться на всех уровнях иерархии.

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

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Без понимания того, что правила оцениваются атомарно, может показаться, что выборка пути /records/ вернет rec1 , но не rec2 . Фактический результат, однако, является ошибкой:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Цель-C
Примечание. Этот продукт Firebase недоступен для цели App Clip.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Быстрый
Примечание. Этот продукт Firebase недоступен для цели App Clip.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Поскольку операция чтения в /records/ является атомарной и не существует правила чтения, предоставляющего доступ ко всем данным в /records/ , это приведет к ошибке PERMISSION_DENIED . Если мы оценим это правило в симуляторе безопасности в нашей консоли Firebase , мы увидим, что операция чтения была отклонена:

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

В операции было отказано, поскольку ни одно правило чтения не разрешало доступ к пути /records/ , но учтите, что правило для rec1 никогда не оценивалось, поскольку оно не входило в запрошенный нами путь. Чтобы получить rec1 , нам нужно будет получить к нему прямой доступ:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Цель-C
Примечание. Этот продукт Firebase недоступен для цели App Clip.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Быстрый
Примечание. Этот продукт Firebase недоступен для цели App Clip.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Переменная местоположения

Rules Realtime Database поддерживают переменную $location для сопоставления сегментов пути. Используйте префикс $ перед сегментом своего пути, чтобы соответствовать вашим правилу с любыми дочерними узлами вдоль пути.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

Вы также можете использовать $variable параллельно с именами постоянных путей.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

,

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

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

Выберите продукт, чтобы узнать больше о его правилах.

Cloud Firestore

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage Используйте следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Следующие ключевые понятия важны для понимания при создании правил:

  • Запрос: метод или методы, вызванные оператором allow . Это методы, которые вы позволяете запускать. Стандартные методы: get , list , create , update и delete . Методы удобства read и write позволяют широкому прочтению и записи доступа к указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в качестве пути URI.
  • Правило: утверждение allow , которое включает в себя условие, которое разрешает запрос, если оно оценивается на истину.

Правила безопасности версии 2

По состоянию на май 2019 года версия 2 правил безопасности Firebase теперь доступна. Версия 2 Правил изменяет поведение рекурсивных подстановочных знаков {name=**} . Вы должны использовать версию 2, если вы планируете использовать запросы группы коллекции . Вы должны выбрать версию 2, создав rules_version = '2'; Первая строка в ваших правилах безопасности:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

Соответствующие пути

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

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

Соответствующие суббочки

Данные в 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>;
    }
  }
}

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

Документ может соответствовать более чем одному заявлению 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.
    match /cities/{document} {
      allow read, write: if true;
    }
  }
}

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

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

Если вы хотите, чтобы правила применялись к произвольно глубокой иерархии, используйте рекурсивный синтаксис подстановочного знака, {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, см. Защитительные запросы группы коллекций .

Пределы правил безопасности

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

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

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

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

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

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

Cloud Storage

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage Используйте следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Следующие ключевые понятия важны для понимания при создании правил:

  • Запрос: метод или методы, вызванные оператором allow . Это методы, которые вы позволяете запускать. Стандартные методы: get , list , create , update и delete . Методы удобства read и write позволяют широкому прочтению и записи доступа к указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в качестве пути URI.
  • Правило: утверждение allow , которое включает в себя условие, которое разрешает запрос, если оно оценивается на истину.

Соответствующие пути

Cloud Storage Security Rules match путям файлов, используемым для доступа к файлам в Cloud Storage . Правила могут match точным путям или путям подстановочного знака, и правила также могут быть вложены. Если правило соответствия не допускает метод запроса, или условие оценивается в false , запрос отрицается.

Точные совпадения

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

Вложенные матчи

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

Подстановочные знаки

Правила также могут использоваться для match шаблону с использованием подстановочных знаков. Подстановочный знак - это названная переменная, которая представляет либо одну строку, такую ​​как profilePhoto.png , или несколько сегментов нескольких путей, таких как images/profilePhoto.png .

Подстановочный знак создается путем добавления вьющихся скобок вокруг имени подстановочного знака, например, {string} . Раблад с несколькими сегментами можно объявить путем добавления =** к имени подстановочного знака, например, {path=**} :

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

Если несколько правил соответствуют файлу, результатом является OR результата всех оценки правил. То есть, если какое -либо правило, соответствие файла оценивается с true , результат true .

В правилах файл «Images/profilephoto.png» может быть прочитал, если либо condition , либо other_condition оценивающие true, в то время как файл «Images/user/user/user: 12345/profilephoto.png» подпадает только от результата other_condition .

Переменная с подстановочным match может быть указана изнутри имени файла или авторизации пути:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage Security Rules не каскада, и правила оцениваются только тогда, когда путь запроса соответствует пути с указанными правилами.

Запросить оценку

Загрузки, загрузки, изменения метаданных и удаления оцениваются с использованием request отправленного в Cloud Storage . Переменная request содержит путь, в котором выполняется запрос, время при получении запроса и новое значение resource , если запрос является записью. Заголовки HTTP и состояние аутентификации также включены.

Объект request также содержит уникальный идентификатор пользователя и полезную нагрузку Firebase Authentication в объекте request.auth , который будет объясняться далее в разделе аутентификации документов.

Полный список свойств в объекте request доступен ниже:

Свойство Тип Описание
auth Карта <строка, строка> Когда пользователь входит в систему, предоставляет uid , уникальный идентификатор пользователя и token , карту аутентификации Firebase Authentication JWT. В противном случае это будет null .
params Карта <строка, строка> Карта, содержащая параметры запроса запроса.
path путь path представляющий путь, который выполняется в.
resource Карта <строка, строка> Новое значение ресурса, присутствующее только по запросам write .
time временная метка Неэппаратная метка, представляющая время сервера, оценивается запрос.

Оценка ресурсов

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

Firebase Security Rules для Cloud Storage предоставляют метаданные файла в объекте resource , который содержит пары ключей/значения метаданных, появляемых в объекте Cloud Storage . Эти свойства могут быть проверены по запросам read или write , чтобы обеспечить целостность данных.

При запросах write (таких как загрузки, обновления метаданных и удаления), в дополнение к объекту resource , который содержит метаданные файла для файла, который существует на пути запроса, у вас также есть возможность использования объекта request.resource , который содержит подмножество метаданных файлов, чтобы записаться, если разрешено. Вы можете использовать эти два значения, чтобы обеспечить целостность данных или применение приложений, такие как тип файла или размер.

Доступен полный список свойств в объекте resource :

Свойство Тип Описание
name нить Полное имя объекта
bucket нить Название ведра. Этот объект находится в.
generation интервал Генерация объектов Google Cloud Storage этого объекта.
metageneration интервал Meta Generation Meta Generation объекта Google Cloud Storage этого объекта.
size интервал Размер объекта в байтах.
timeCreated временная метка Временная метка, представляющая время, созданное объектом.
updated временная метка Неэппаратная метка, представляющая время, которое объект в последний раз обновлялся.
md5Hash нить Хеш MD5 объекта.
crc32c нить Хеш CRC32C объекта.
etag нить ETAG, связанный с этим объектом.
contentDisposition нить Содержимое расположение, связанное с этим объектом.
contentEncoding нить Кодирование контента, связанное с этим объектом.
contentLanguage нить Контент, связанный с этим объектом.
contentType нить Тип контента, связанный с этим объектом.
metadata Карта <строка, строка> Пары ключей/значения дополнительных, разработчик указал пользовательские метаданные.

request.resource содержит все это, за исключением generation , metageneration , etag , timeCreated и updated .

Правила безопасности укрепляются

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

Лимит Подробности
Максимальное количество firestore.exists() и firestore.get() вызовы за запрос

2 для запросов на однодокумент и запросов на запросы.

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

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

Полный пример

Собрав все это вместе, вы можете создать полный пример правил для решения для хранения изображений:

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) Filename (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow read;
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

Realtime Database

Базовая структура

В Realtime Database Firebase Security Rules состоят из выражений, подобных JavaScript, содержащихся в документе JSON.

Они используют следующий синтаксис:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

В правиле есть три основных элемента:

  • Путь: расположение базы данных. Это отражает структуру JSON вашей базы данных.
  • Запрос: это методы, которые правило использует для предоставления доступа. Правила read и write предоставляют широкий доступ к чтению и записи, в то время как validate правил закона в качестве вторичной проверки для предоставления доступа на основе входящих или существующих данных.
  • Условие: условие, которое разрешает запрос, если он оценивается на истину.

Как правила применяются к путям

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

Рассмотрим следующие правила:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

Эта структура безопасности позволяет /bar/ считываться, когда /foo/ содержит дочерний baz со значением true . ".read": false правило под /foo/bar/ не оказывает здесь никакого влияния, поскольку доступ не может быть отозван дочерним путем.

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

Тем не менее, .validate . Все правила проверки должны быть удовлетворены на всех уровнях иерархии для разрешения записи.

Кроме того, поскольку правила не применяются обратно к родительскому пути, прочтите или записывают операцию, если нет правила в запрошенном месте или в родительском месте, которое предоставляет доступ. Даже если каждый пострадавший дочерний путь доступен, чтение в родительском месте полностью потерпит неудачу. Рассмотрим эту структуру:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Без понимания того, что правила оцениваются атомно, может показаться, что извлечение /records/ пути возвращает rec1 , но не rec2 . Фактический результат, однако, является ошибкой:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Цель-C
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Быстрый
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Поскольку операция чтения AT /records/ является атомной, и нет никакого правила чтения, которое предоставляет доступ ко всем данным в соответствии с /records/ , это приведет к ошибке PERMISSION_DENIED . Если мы оценим это правило в симуляторе безопасности в нашей консоли Firebase , мы увидим, что операция чтения была отклонена:

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

Операция была отклонена, потому что правило чтения не допустило доступа к /records/ пути, но обратите внимание, что правило для rec1 никогда не было оценено, потому что оно не было на пути, который мы просили. Чтобы получить rec1 , нам нужно получить доступ к нему напрямую:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Цель-C
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Быстрый
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Переменная местоположения

Rules Realtime Database поддерживают переменную $location для соответствия сегментам пути. Используйте префикс $ перед сегментом своего пути, чтобы соответствовать вашим правилу с любыми дочерними узлами вдоль пути.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

Вы также можете использовать $variable параллельно с именами постоянных путей.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

,

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

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

Выберите продукт, чтобы узнать больше о его правилах.

Cloud Firestore

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage Используйте следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Следующие ключевые понятия важны для понимания при создании правил:

  • Запрос: метод или методы, вызванные оператором allow . Это методы, которые вы позволяете запускать. Стандартные методы: get , list , create , update и delete . Методы удобства read и write позволяют широкому прочтению и записи доступа к указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в качестве пути URI.
  • Правило: утверждение allow , которое включает в себя условие, которое разрешает запрос, если оно оценивается на истину.

Правила безопасности версии 2

По состоянию на май 2019 года версия 2 правил безопасности Firebase теперь доступна. Версия 2 Правил изменяет поведение рекурсивных подстановочных знаков {name=**} . Вы должны использовать версию 2, если вы планируете использовать запросы группы коллекции . Вы должны выбрать версию 2, создав rules_version = '2'; Первая строка в ваших правилах безопасности:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

Соответствующие пути

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

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

Соответствующие суббочки

Данные в 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>;
    }
  }
}

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

Документ может соответствовать более чем одному заявлению 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.
    match /cities/{document} {
      allow read, write: if true;
    }
  }
}

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

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

Если вы хотите, чтобы правила применялись к произвольно глубокой иерархии, используйте рекурсивный синтаксис подстановочного знака, {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, см. Защитительные запросы группы коллекций .

Пределы правил безопасности

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

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

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

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

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

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

Cloud Storage

Базовая структура

Firebase Security Rules в Cloud Firestore и Cloud Storage Используйте следующую структуру и синтаксис:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Следующие ключевые понятия важны для понимания при создании правил:

  • Запрос: метод или методы, вызванные оператором allow . Это методы, которые вы позволяете запускать. Стандартные методы: get , list , create , update и delete . Методы удобства read и write позволяют широкому прочтению и записи доступа к указанной базе данных или пути хранения.
  • Путь: база данных или место хранения, представленное в качестве пути URI.
  • Правило: утверждение allow , которое включает в себя условие, которое разрешает запрос, если оно оценивается на истину.

Соответствующие пути

Cloud Storage Security Rules match путям файлов, используемым для доступа к файлам в Cloud Storage . Правила могут match точным путям или путям подстановочного знака, и правила также могут быть вложены. Если правило соответствия не допускает метод запроса, или условие оценивается в false , запрос отрицается.

Точные совпадения

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

Вложенные матчи

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

Подстановочные знаки

Правила также могут использоваться для match шаблону с использованием подстановочных знаков. Подстановочный знак - это названная переменная, которая представляет либо одну строку, такую ​​как profilePhoto.png , или несколько сегментов нескольких путей, таких как images/profilePhoto.png .

Подстановочный знак создается путем добавления вьющихся скобок вокруг имени подстановочного знака, например, {string} . Раблад с несколькими сегментами можно объявить путем добавления =** к имени подстановочного знака, например, {path=**} :

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

Если несколько правил соответствуют файлу, результатом является OR результата всех оценки правил. То есть, если какое -либо правило, соответствие файла оценивается с true , результат true .

В правилах файл «Images/profilephoto.png» может быть прочитал, если либо condition , либо other_condition оценивающие true, в то время как файл «Images/user/user/user: 12345/profilephoto.png» подпадает только от результата other_condition .

Переменная с подстановочным match может быть указана изнутри имени файла или авторизации пути:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage Security Rules не каскада, и правила оцениваются только тогда, когда путь запроса соответствует пути с указанными правилами.

Запросить оценку

Загрузки, загрузки, изменения метаданных и удаления оцениваются с использованием request отправленного в Cloud Storage . Переменная request содержит путь, в котором выполняется запрос, время при получении запроса и новое значение resource , если запрос является записью. Заголовки HTTP и состояние аутентификации также включены.

Объект request также содержит уникальный идентификатор пользователя и полезную нагрузку Firebase Authentication в объекте request.auth , который будет объясняться далее в разделе аутентификации документов.

Полный список свойств в объекте request доступен ниже:

Свойство Тип Описание
auth Карта <строка, строка> Когда пользователь входит в систему, предоставляет uid , уникальный идентификатор пользователя и token , карту аутентификации Firebase Authentication JWT. В противном случае это будет null .
params Карта <строка, строка> Карта, содержащая параметры запроса запроса.
path путь path представляющий путь, который выполняется в.
resource Карта <строка, строка> Новое значение ресурса, присутствующее только по запросам write .
time временная метка Неэппаратная метка, представляющая время сервера, оценивается запрос.

Оценка ресурсов

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

Firebase Security Rules для Cloud Storage предоставляют метаданные файла в объекте resource , который содержит пары ключей/значения метаданных, появляемых в объекте Cloud Storage . Эти свойства могут быть проверены по запросам read или write , чтобы обеспечить целостность данных.

При запросах write (таких как загрузки, обновления метаданных и удаления), в дополнение к объекту resource , который содержит метаданные файла для файла, который существует на пути запроса, у вас также есть возможность использования объекта request.resource , который содержит подмножество метаданных файлов, чтобы записаться, если разрешено. Вы можете использовать эти два значения, чтобы обеспечить целостность данных или применение приложений, такие как тип файла или размер.

Доступен полный список свойств в объекте resource :

Свойство Тип Описание
name нить Полное имя объекта
bucket нить Название ведра. Этот объект находится в.
generation интервал Генерация объектов Google Cloud Storage этого объекта.
metageneration интервал Meta Generation Meta Generation объекта Google Cloud Storage этого объекта.
size интервал Размер объекта в байтах.
timeCreated временная метка Временная метка, представляющая время, созданное объектом.
updated временная метка Неэппаратная метка, представляющая время, которое объект в последний раз обновлялся.
md5Hash нить Хеш MD5 объекта.
crc32c нить Хеш CRC32C объекта.
etag нить ETAG, связанный с этим объектом.
contentDisposition нить Содержимое расположение, связанное с этим объектом.
contentEncoding нить Кодирование контента, связанное с этим объектом.
contentLanguage нить Контент, связанный с этим объектом.
contentType нить Тип контента, связанный с этим объектом.
metadata Карта <строка, строка> Пары ключей/значения дополнительных, разработчик указал пользовательские метаданные.

request.resource содержит все это, за исключением generation , metageneration , etag , timeCreated и updated .

Правила безопасности укрепляются

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

Лимит Подробности
Максимальное количество firestore.exists() и firestore.get() вызовы за запрос

2 для запросов на однодокумент и запросов на запросы.

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

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

Полный пример

Собрав все это вместе, вы можете создать полный пример правил для решения для хранения изображений:

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) Filename (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow read;
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

Realtime Database

Базовая структура

В Realtime Database Firebase Security Rules состоят из выражений, подобных JavaScript, содержащихся в документе JSON.

Они используют следующий синтаксис:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

В правиле есть три основных элемента:

  • Путь: расположение базы данных. Это отражает структуру JSON вашей базы данных.
  • Запрос: это методы, которые правило использует для предоставления доступа. Правила read и write предоставляют широкий доступ к чтению и записи, в то время как validate правил закона в качестве вторичной проверки для предоставления доступа на основе входящих или существующих данных.
  • Условие: условие, которое разрешает запрос, если он оценивается на истину.

Как правила применяются к путям

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

Рассмотрим следующие правила:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

Эта структура безопасности позволяет /bar/ считываться, когда /foo/ содержит дочерний baz со значением true . ".read": false правило под /foo/bar/ не оказывает здесь никакого влияния, поскольку доступ не может быть отозван дочерним путем.

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

Тем не менее, .validate . Все правила проверки должны быть удовлетворены на всех уровнях иерархии для разрешения записи.

Кроме того, поскольку правила не применяются обратно к родительскому пути, прочтите или записывают операцию, если нет правила в запрошенном месте или в родительском месте, которое предоставляет доступ. Даже если каждый пострадавший дочерний путь доступен, чтение в родительском месте полностью потерпит неудачу. Рассмотрим эту структуру:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Без понимания того, что правила оцениваются атомно, может показаться, что извлечение /records/ пути возвращает rec1 , но не rec2 . Фактический результат, однако, является ошибкой:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Цель-C
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Быстрый
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Поскольку операция чтения AT /records/ является атомной, и нет никакого правила чтения, которое предоставляет доступ ко всем данным в соответствии с /records/ , это приведет к ошибке PERMISSION_DENIED . Если мы оценим это правило в симуляторе безопасности в нашей консоли Firebase , мы увидим, что операция чтения была отклонена:

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

Операция была отклонена, потому что правило чтения не допустило доступа к /records/ пути, но обратите внимание, что правило для rec1 никогда не было оценено, потому что оно не было на пути, который мы просили. Чтобы получить rec1 , нам нужно получить доступ к нему напрямую:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Цель-C
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Быстрый
Примечание. Этот продукт Firebase недоступен в целевой цели клипа.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Ява
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
ОТДЫХ
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Переменная местоположения

Realtime Database Rules support a $location variable to match path segments. Use the $ prefix in front of your path segment to match your rule to any child nodes along the path.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

You can also use the $variable in parallel with constant path names.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }