Справочник по правилам безопасности Firebase для облачного хранилища

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

Правило

rule — это выражение, которое оценивается, чтобы определить, разрешено ли request выполнить желаемое действие.

Типы

Позволять

Правила allow состоят из метода, например read или write , а также необязательного условия. Когда правило выполняется, условие оценивается, и если условие оценивается как true , желаемый метод разрешен; в противном случае метод отклоняется. Правило allow без условий всегда разрешает нужный метод.

// Always allow method
allow <method>;

// Allow method if condition is true
allow <method>: if <condition>;

В настоящее время allow — единственный поддерживаемый тип правила.

Методы запроса

Читать

Метод read охватывает все запросы, в которых читаются данные или метаданные файла, включая загрузку файлов и чтение метаданных файлов.

// Always allow reads
allow read;

// Allow reads if condition evaluates to true
allow read: if <condition>;

Писать

Метод write охватывает все запросы, в которых записываются данные или метаданные файла, включая загрузку файлов, удаление файлов и обновление метаданных файлов.

// Always allow writes
allow write;

// Allow writes if condition evaluates to true
allow write: if <condition>;

Соответствовать

Правила выполняются, когда request пользователя (например, загрузка или загрузка файла) соответствует пути к файлу, охватываемому правилом. match состоит из пути и тела, которое должно содержать хотя бы одно allow правило. Если ни один путь не найден, запрос отклоняется.

Вы можете match полностью именованный путь или вставить подстановочные знаки, чтобы сопоставить все пути, соответствующие определенному шаблону.

Сегменты пути

single_segment

Вы можете использовать отдельные сегменты пути, чтобы создать правило, соответствующее файлу, хранящемуся в Cloud Storage.

// Allow read at "path" if condition evaluates to true
match /path {
  allow read: if <condition>;
}

Также разрешены несколько сегментов пути и вложенные пути:

// Allow read at "path/to/object" if condition evaluates to true
match /path {
  match /to {
    match /object {
      allow read: if <condition>;
    }
  }
}

{single_segment_wildcard}

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

// Allow read at any path "/*", if condition evaluates to true
match /{single_path} {
  // Matches "path", "to", or "object" but not "path/to/object"
  allow read: if <condition>;
}

Несколько сегментов пути и вложенные пути также могут иметь подстановочные знаки:

// Allow read at any path "/path/*/newPath/*", if condition evaluates to true
match /path/{first_wildcard} {
  match /newPath/{second_wildcard} {
    // Matches "path/to/newPath/newObject" or "path/from/newPath/oldObject"
    allow read: if <condition>;
  }
}

{multi_segment_wildcard=**}

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

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

// Allow read at any path "/**", if condition evaluates to true
match /{multi_path=**} {
  // Matches anything at or below this, from "path", "path/to", "path/to/object", ...
  allow read: if <condition>;
}

Запрос

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

Характеристики

auth

Когда аутентифицированный пользователь выполняет запрос к Cloud Storage, переменная auth заполняется uid пользователя ( request.auth.uid ), а также утверждениями JWT аутентификации Firebase ( request.auth.token ).

request.auth.token содержит некоторые или все следующие ключи:

Поле Описание
email Адрес электронной почты, связанный с учетной записью, если таковой имеется.
email_verified true , если пользователь подтвердил, что у него есть доступ к адресу email . Некоторые провайдеры автоматически проверяют принадлежащие им адреса электронной почты.
phone_number Номер телефона, связанный с учетной записью, если он присутствует.
name Отображаемое имя пользователя, если оно установлено.
sub UID пользователя Firebase. Это уникально в рамках проекта.
firebase.identities Словарь всех идентификаторов, связанных с учетной записью этого пользователя. Ключами словаря могут быть любые из следующих: email , phone , google.com , facebook.com , github.com , twitter.com . Значения словаря представляют собой массивы уникальных идентификаторов для каждого поставщика удостоверений, связанного с учетной записью. Например, auth.token.firebase.identities["google.com"][0] содержит первый идентификатор пользователя Google, связанный с учетной записью.
firebase.sign_in_provider Поставщик входа, использованный для получения этого токена. Может быть одной из следующих строк: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com .
firebase.tenant TenantId, связанный с учетной записью, если он присутствует. например, tenant2-m6tyz

При использовании пользовательской аутентификации request.auth.token также содержит любые пользовательские утверждения, указанные разработчиком.

Когда неаутентифицированный пользователь выполняет запрос, request.auth имеет значение null .

// Allow requests from authenticated users
allow read, write: if request.auth != null;

path

Переменная path содержит путь, по которому выполняется request .

// Allow a request if the first path segment equals "images"
allow read, write: if request.path[0] == 'images';

resource

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

// Allow a request if the new value is smaller than 5MB
allow read, write: if request.resource.size < 5 * 1024 * 1024;

request.resource содержит следующие свойства из resource :

Свойство
name
bucket
metadata
size
contentType

time

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

// Allow a read if the file was created less than one hour ago
allow read: if request.time < resource.timeCreated + duration.value(1, 'h');

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

Ресурс

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

Характеристики

name

Строка, содержащая полное имя файла, включая путь к файлу.

// Allow reads if the resource name is "path/to/object"
allow read: if resource.name == 'path/to/object'

bucket

Строка, содержащая сегмент Google Cloud Storage, в котором хранится этот файл.

// Allow reads of all resources in your bucket
allow read: if resource.bucket == '<your-cloud-storage-bucket>'

generation

Целое число, содержащее созданный объект Google Cloud Storage для файла. Используется для управления версиями объектов.

// Allow reads if the resource matches a known object version
allow read: if resource.generation == <known-generation>

metageneration

Целое число, содержащее метагенерацию объекта Google Cloud Storage файла. Используется для управления версиями объектов.

// Allow reads if the resource matches a known object metadata version
allow read: if resource.metageneration == <known-generation>

size

Целое число, содержащее размер файла в байтах.

// Allow reads if the resource is less than 10 MB
allow read: if resource.size < 10 * 1024 * 1024;

timeCreated

Временная метка, указывающая, когда был создан файл.

// Allow reads if the resource was created less than an hour ago
allow read: if resource.timeCreated < request.time + duration.value(60, "m")

updated

Временная метка, показывающая, когда файл был последний раз обновлен.

// Allow reads if the resource was updated less than an hour ago
allow read: if resource.updated < request.time + duration.value(60, "m")

md5Hash

Строка, содержащая MD5-хеш файла.

// Allow writes if the hash of the uploaded file is the same as the existing file
allow write: if request.resource.md5Hash == resource.md5Hash;

crc32c

Строка, содержащая хэш crc32c файла.

// Allow writes if the hash of the uploaded file is the same as the existing file
allow write: if request.resource.crc32c == resource.crc32c;

etag

Строка, содержащая etag файла.

// Allow writes if the etag matches a known object etag
allow write: if resource.etag == <known-generation>

contentDisposition

Строка, содержащая расположение содержимого файла.

// Allow reads if the content disposition matches a certain value
allow read: if resource.contentDisposition == 'inlined';

contentEncoding

Строка, содержащая кодировку содержимого файла.

// Allow reads if the content is encoded with gzip
allow read: if resource.contentEncoding == 'gzip';

contentLanguage

Строка, содержащая язык содержимого файла.

// Allow reads if the content language is Japanese
allow read: if resource.contentLanguage == 'ja';

contentType

Строка, содержащая тип содержимого файла.

// Allow reads if the content type is PNG.
allow read: if resource.contentType == 'image/png';

metadata

Map<String, String> , содержащий дополнительные поля метаданных, предоставленные разработчиком.

// Allow reads if a certain metadata field matches a desired value
allow read: if resource.metadata.customProperty == 'customValue';

firestore.get и firestore.exists

Функции firestore.get() и firestore.exists() позволяют получать доступ к документам в Cloud Firestore для оценки сложных критериев авторизации.

Обе функции firestore.get() и firestore.exists() ожидают полностью заданных путей к документам. При использовании переменных для создания путей для firestore.get() и firestore.exists() вам необходимо явно экранировать переменные, используя синтаксис $(variable) .

firestore.get

Получите содержимое документа Cloud Firestore.

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{club}/files/{fileId} {
      allow read: if club in
        firestore.get(/databases/(default)/documents/users/$(request.auth.uid)).data.memberships
    }
  }
}

firestore.exists

Проверьте, существует ли документ Cloud Firestore.

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/photos/{fileId} {
      allow read: if
        firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.uid))
    }
  }
}

Услуга

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

Имя

name

К имени будут применяться правила сервиса. Единственное текущее значение — firebase.storage .

// Specify the service name
service firebase.storage {
  match /b/{bucket}/o {
    ...
  }
}

Типы данных

Язык правил позволяет проверять тип с помощью оператора is .

// For example
a is null
a is string

null

Тип данных null представляет несуществующее значение.

allow read: if request.auth != null;

bool

Тип bool представляет логическое значение true или false .

allow read: if true;   // always succeeds
allow write: if false; // always fails

Сравнение

Логические значения можно сравнивать с помощью операторов == != .

Логические операции

Операция Выражение
AND x && y
OR x || y
NOT !x

Операции являются коротким замыканием и могут возвращать true , false или Error .

allow read: if true || false;   // always succeeds, short circuits at true
allow write: if false && true; // always fails, short circuits at false

int и float

Типы int и float представляют числа. Целые числа: 0 , 1 , -2 и т. д., а числа с плавающей запятой: 1.0 , -2.0 , 3.33 и т. д.

Целые числа — это 64-битные значения со знаком, а числа с плавающей точкой — 64-битные значения, соответствующие стандарту IEEE 754. Значения типа int будут принудительно преобразованы в float при использовании в сравнениях и арифметических операциях со значением с float .

Сравнение

Целые числа и числа с плавающей запятой можно сравнивать и упорядочивать с помощью операторов == , != , > , < , >= и <= .

Арифметика

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

Операция Выражение
Добавление x + y
Вычитание x - y
Умножение x * y
Разделение x / y
по модулю x % y
Отрицание -x

Математические функции

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

Функция Описание
math.ceil(x) Потолок числового значения
math.floor(x) Минимальное числовое значение
math.round(x) Округлите входное значение до ближайшего целого числа
math.abs(x) Абсолютное значение входа
math.isInfinite(x) Проверяет, равно ли значение ±∞ , возвращает bool
math.isNaN(x) Проверьте, не является ли значение числом NaN , возвращает bool

string

Сравнение

Строки можно лексографически сравнивать и упорядочивать с помощью операторов == , != , > , < , >= и <= .

Конкатенация

Строки можно объединить с помощью оператора + .

// Concatenate a file name and extension
'file' + '.txt'

Индекс и диапазон

Оператор index string[] возвращает строку, содержащую символ по указанному индексу в строке.

// Allow reads of files that begin with 'a'
match /{fileName} {
  allow read: if fileName[0] == 'a';
}

Оператор range string[i:j] возвращает строку, содержащую символы между указанными индексами, от i (включительно) до j (исключительно). Если i или j не указаны, они по умолчанию равны 0 и размеру строки соответственно, но для того, чтобы диапазон был допустимым, необходимо указать хотя бы i или j .

// Allow reads of files that begin with 'abcdef'
match /{fileName} {
  allow read: if fileName[0:6] == 'abcdef';
}

Операторы index и range выдадут ошибку, если предоставленные индексы выходят за границы строки.

size

Возвращает количество символов в строке.

// Allow files with names less than 10 characters
match /{fileName} {
  allow write: if fileName.size() < 10;
}

matches

Выполняет сопоставление с регулярным выражением и возвращает true , если строка соответствует данному регулярному выражению. Использует синтаксис Google RE2 .

// Allow writes to files which end in ".txt"
match /{fileName} {
  allow write: if fileName.matches('.*\\.txt')
}

split

Разбивает строку в соответствии с предоставленным регулярным выражением и возвращает list строк. Использует синтаксис Google RE2 .

// Allow files named "file.*" to be uploaded
match /{fileName} {
  allow write: if fileName.split('.*\\..*')[0] == 'file'
}

path

Пути — это имена, подобные каталогам, с необязательным сопоставлением с образцом. Наличие косой черты / обозначает начало сегмента пути.

path

Преобразует string аргумент в path .

// Allow reads on a specific file path
match /{allFiles=**} {
  allow read: if allFiles == path('/path/to/file');
}

timestamp

Временные метки указаны в формате UTC, возможные значения начинаются с 0001-01-01T00.00.00Z и заканчиваются 9999-12-31T23.59.59Z.

Сравнение

Временные метки можно сравнивать и упорядочивать с помощью операторов == , != , > , < , >= и <= .

Арифметика

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

Выражение Результат
timestamp + duration timestamp
duration + timestamp timestamp
timestamp - duration timestamp
timestamp - timestamp duration
duration + duration duration
duration - duration duration

date

Значение timestamp , содержащее только year , month и day .

// Allow reads on the same day that the resource was created.
allow read: if request.time.date() == resource.timeCreated.date()

year

Значение года в виде целого числа от 1 до 9999.

// Allow reads on all requests made before 2017
allow read: if request.time.year() < 2017

month

Значение месяца в виде целого числа от 1 до 12.

// Allow reads on all requests made during the month of January
allow read: if request.time.month() == 1;

day

Текущий день месяца в формате int, от 1 до 31.

// Allow reads on all requests made during the first day of each month
allow read: if request.time.day() == 1;

time

Значение duration , содержащее текущее время.

// Allow reads on all requests made before 12PM
allow read: if request.time.time() < duration.time(12, 0, 0, 0);

hours

Значение часов представляет собой целое число от 0 до 23.

// Allow reads on all requests made before 12PM
allow read: if request.time.hours() < 12;

minutes

Значение минут в виде целого числа от 0 до 59.

// Allow reads during even minutes of every hour
allow read: if request.time.minutes() % 2 == 0;

seconds

Значение секунд в виде целого числа от 0 до 59.

// Allow reads during the second half of each minute
allow read: if request.time.seconds() > 29;

nanos

Доли секунды в нано как целое число.

// Allow reads during the first 0.1 seconds of each second
allow read: if request.time.nanos() < 100000000;

dayOfWeek

День недели: от 1 (понедельник) до 7 (воскресенье).

// Allow reads on weekdays (Monday to Friday)
allow read: if request.time.dayOfWeek() < 6;

dayOfYear

День текущего года, от 1 до 366.

// Allow reads every fourth day
allow read: if request.time.dayOfYear() % 4 == 0;

toMillis

Возвращает текущее количество миллисекунд, прошедших с эпохи Unix.

// Allow reads if the request is made before a specified time
allow read: if request.time.toMillis() < <milliseconds>;

duration

Значения продолжительности представлены в виде секунд плюс доли секунды в наносекундах.

Сравнение

Продолжительность можно сравнивать и упорядочивать с помощью операторов == , != , > , < , >= и <= .

Арифметика

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

Выражение Результат
timestamp + duration timestamp
duration + timestamp timestamp
timestamp - duration timestamp
timestamp - timestamp duration
duration + duration duration
duration - duration duration

seconds

Количество секунд в текущей продолжительности. Должно быть между -315 576 000 000 и +315 576 000 000 включительно.

nanos

Количество долей секунды (в наносекундах) текущей продолжительности. Должно быть от -999 999 999 до +999 999 999 включительно. Для ненулевых секунд и ненулевых наносекунд знаки обоих должны совпадать.

duration.value

Длительность можно создать с помощью функции duration.value(int magnitude, string units) , которая создает длительность времени на основе заданной величины и единицы измерения.

// All of these durations represent one hour:
duration.value(1, "h")
duration.value(60, "m")
duration.value(3600, "s")

Возможные unit измерения:

Продолжительность unit
Недели w
Дни d
Часы h
Минуты m
Секунды s
Миллисекунды ms
Наносекунды ns

duration.time

Длительность может быть создана с помощью функции duration.time(int hours, int minutes, int seconds, int nanoseconds) , которая создает длительность времени, равную заданным часам, минутам, секундам и наносекундам.

// Create a four hour, three minute, two second, one nanosecond duration
duration.time(4, 3, 2, 1)

list

Список содержит упорядоченный массив значений, который может иметь тип: null , bool , int , float , string , path , list , map , timestamp или duration .

Учитывая x и y list типов и i и j типа int

Создание

Чтобы создать список, добавьте значения в скобках:

// Create a list of strings
['apples', 'grapes', 'bananas', 'cheese', 'goats']

Сравнение

Списки можно сравнивать с помощью операторов == != . Равенство двух списков требует, чтобы все значения были равны.

Индекс и диапазон

Оператор index list[] возвращает элемент по указанному индексу в списке.

// Allow reads of all files that begin with 'a'
match /{fileName} {
  allow read: if fileName[0] == 'a';
}

Оператор range list[i:j] возвращает все элементы списка между указанными индексами от i (включительно) до j (исключительно). Если i или j не указаны, они по умолчанию равны 0 и размеру списка соответственно, но для того, чтобы диапазон был действительным, необходимо указать хотя бы i или j .

// Allow reads of all files that begin with 'abcdef'
match /{fileName} {
  allow read: if fileName[0:6] == 'abcdef';
}

in

Возвращает true , если желаемое значение присутствует в списке, или false , если оно отсутствует.

// Allow read if a filename has the string 'txt' in it
match /{fileName} {
  allow read: if 'txt' in fileName.split('\\.');
}

join

Объединяет список строк в одну строку, разделенную заданной строкой.

// Allow reads if the joined array is 'file.txt'
allow read: if ['file', 'txt'].join('.') == 'file.txt';

size

Количество элементов в списке.

// Allow read if there are three items in our list
allow read: if ['foo', 'bar', 'baz'].size() == 3;

hasAll

Возвращает true , если в списке присутствуют все значения.

// Allow read if one list has all items in the other list
allow read: if ['file', 'txt'].hasAll(['file', 'txt']);

map

Карта содержит пары ключ/значение, где ключи представляют собой строки, а значения могут быть любыми из: null , bool , int , float , string , path , list , map , timestamp или duration .

Создание

Чтобы создать карту, добавьте пары ключ/значение между фигурными скобками:

// Create a map of strings to strings
{
  'mercury': 'mars',
  'rain': 'cloud',
  'cats': 'dogs',
}

Сравнение

Карты можно сравнивать с помощью операторов == != . Равенство двух карт требует, чтобы все ключи присутствовали на обеих картах и ​​все значения были равны.

Индекс

Доступ к значениям на карте осуществляется с помощью скобок или точечной записи:

// Access custom metadata properties
allow read: if resource.metadata.property == 'property'
allow write: if resource.metadata['otherProperty'] == 'otherProperty'

Если ключ отсутствует, будет возвращена error .

in

Возвращает true , если нужный ключ присутствует в карте, или false , если он отсутствует.

// Allow reads if a property is present in the custom metadata
allow read: if property in resource.metadata;

size

Количество ключей в карте.

// Allow reads if there's exactly one custom metadata key
allow read: if resource.metadata.size() == 1;

keys

Список всех ключей на карте.

// Allow reads if the first metadata key is 'myKey'
allow read: if resource.metadata.keys()[0] == 'myKey';

values

Список всех значений на карте в ключевом порядке.

// Allow reads if the first metadata value is 'myValue'
allow read: if resource.metadata.values()[0] == 'myValue';

Ошибки

Оценка ошибок

Правила безопасности Firebase для облачного хранилища продолжают оценку при обнаружении ошибок. Это полезно, поскольку условные операторы && и || выражения могут поглощать ошибку, если в противном случае условное выражение превратилось бы в false или true соответственно. Например:

Выражение Результат
error && true error
error && false false
error || true true
error || false error

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

// Error if resource.size is zero
allow read: if 1000000 / resource.size;

// Error, key doesn't exist
allow read: if resource.metadata.nonExistentKey == 'value';

// Error, no unit 'y' exists
allow read: if request.time < resource.timeCreated + duration.value(1, 'y');