Условия использования в правилах безопасности облачного хранилища Firebase

Это руководство основано на изучении основного синтаксиса руководства по языку Firebase Security Rules и показывает, как добавлять условия в Firebase Security Rules для Cloud Storage .

Основным строительным блоком Cloud Storage Security Rules является условие . Условие — это логическое выражение, которое определяет, следует ли разрешить или запретить определенную операцию. Для базовых правил использование литералов true и false в качестве условий работает отлично. Но язык Firebase Security Rules для Cloud Storage дает вам возможность писать более сложные условия, которые могут:

  • Проверьте аутентификацию пользователя
  • Проверка входящих данных

Аутентификация

Firebase Security Rules for Cloud Storage интегрируется с Firebase Authentication для предоставления мощной аутентификации на основе пользователя в Cloud Storage . Это позволяет осуществлять детальный контроль доступа на основе утверждений токена Firebase Authentication .

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

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

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

Используя эти данные, существует несколько распространенных способов использования аутентификации для защиты файлов:

  • Публичный: игнорировать request.auth
  • Аутентифицированный частный: проверьте, что request.auth не null
  • Пользовательский приватный: проверьте, что request.auth.uid равен uid пути
  • Групповая частная: проверьте утверждения пользовательского токена на соответствие выбранному утверждению или прочитайте метаданные файла, чтобы узнать, существует ли поле метаданных

Публичный

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

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

Аутентифицированный частный

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

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

Пользователь личный

Наиболее распространенным вариантом использования request.auth будет предоставление отдельным пользователям детализированных разрешений на доступ к их файлам: от загрузки фотографий профиля до чтения личных документов.

Поскольку файлы в Cloud Storage имеют полный «путь» к файлу, все, что нужно для того, чтобы сделать файл контролируемым пользователем, — это фрагмент уникальной идентифицирующей пользователя информации в префиксе имени файла (например, uid пользователя), который можно проверить при оценке правила:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth.uid == userId;
}

Группа частная

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

  • Создайте пользовательский токен Firebase Authentication , содержащий дополнительную информацию об участнике группы (например, идентификатор группы).
  • Включить информацию о группе (например, идентификатор группы или список авторизованных uid ) в метаданные файла

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

// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}

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

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

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

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

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

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

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

Firebase Security Rules for 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 нить Тег e, связанный с этим объектом.
contentDisposition нить Расположение контента, связанного с этим объектом.
contentEncoding нить Кодировка содержимого, связанная с этим объектом.
contentLanguage нить Язык контента, связанный с этим объектом.
contentType нить Тип контента, связанный с этим объектом.
metadata карта<строка, строка> Пары ключ/значение дополнительных, указанных разработчиком пользовательских метаданных.

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

Улучшение с помощью Cloud Firestore

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

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

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

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.id)).memberships
    }
  }
}
В следующем примере фотографии пользователя могут видеть только его друзья.
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.id))
    }
  }
}

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

Вы можете отключить эту функцию, удалив роль IAM, как описано в разделе Управление и развертывание Firebase Security Rules .

Проверить данные

Firebase Security Rules для Cloud Storage также можно использовать для проверки данных, включая проверку имени файла и пути, а также свойств метаданных файла, таких как contentType и size .

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

Пользовательские функции

По мере того, как ваши Firebase Security Rules становятся более сложными, вы можете захотеть обернуть наборы условий в функции, которые вы можете повторно использовать в вашем наборе правил. Правила безопасности поддерживают пользовательские функции. Синтаксис для пользовательских функций немного похож на JavaScript, но функции Firebase Security Rules написаны на доменно-специфичном языке, который имеет некоторые важные ограничения:

  • Функции могут содержать только один оператор return . Они не могут содержать никакой дополнительной логики. Например, они не могут выполнять циклы или вызывать внешние службы.
  • Функции могут автоматически получать доступ к функциям и переменным из области, в которой они определены. Например, функция, определенная в области service firebase.storage имеет доступ к переменной resource , а для Cloud Firestore — только к встроенным функциям, таким как get() и exists() .
  • Функции могут вызывать другие функции, но не могут рекурсировать. Общая глубина стека вызовов ограничена 10.
  • В версии rules2 функции могут определять переменные с помощью ключевого слова let . Функции могут иметь любое количество привязок let, но должны заканчиваться оператором return.

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

service firebase.storage {
  match /b/{bucket}/o {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }
    match /images/{imageId} {
      allow read, write: if signedInOrPublic();
    }
    match /mp3s/{mp3Ids} {
      allow read: if signedInOrPublic();
    }
  }
}

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

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

После этого обсуждения условий вы получите более глубокое понимание Правил и будете готовы:

Узнайте, как обрабатывать основные варианты использования, а также ознакомьтесь с рабочим процессом разработки, тестирования и развертывания правил: