Правила Firestore: извлекать поток сообщений по threadId безопасным способом - PullRequest
0 голосов
/ 23 февраля 2020

Допущения

Я использую Firestore и не могу установить для него правильное правило.

Предположим, есть приложение для чата.
И есть потоков и сообщений коллекций.

потоки атрибуты

создалAt
userAId
userBId

сообщения атрибуты

threadId
senderId
receiveId

Я установил правило безопасности следующим образом, так как я не хочу, чтобы мои пользователи видели сообщения других пользователей (пропущено нерелевантная часть):

match /messages/{messageId} {
  allow read: if isAuthenticated() && 
  (request.auth.uid == resource.data.senderId || request.auth.uid == resource.data.receiverId);
}

Предположим, у нас есть только один поток и только одно сообщение этого потока, сохраненное в firestore.

Проблема

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

const querySnapshot = await firebase.firestore()
    .collection('messages')
    .where('threadId', '==', someThreadId)
    .get()

Однако, когда я выполняю следующий запрос это извлекает сообщение по documentId, оно возвращает сообщение успешно.

const documentQuerySnapshot = await firebase.firestore()
    .collection('messages')
    .doc(specificMessageId)
    .get()

Обходной путь

Я вынужден написать 2 запроса, и я не хочу, так как это не эффективно.

const qs1 = await firebase.firestore()
  .collection('messages')
  .where('senderId', '==', someUserId)
  .where('threadId', '==', someThreadId)
  .get()

const qs2 = await firebase.firestore()
  .collection('messages')
  .where('receiverId', '==', someUserId)
  .where('threadId', '==', someThreadId)
  .get()

messages = ${merge 2 messages list above}

Quesetion

Как получить все сообщения потока по threadId при установке правильных правил безопасности, чтобы сообщения не читались другими пользователями?

1 Ответ

1 голос
/ 23 февраля 2020

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

Поскольку ваши правила допускают только чтение сообщений, которые имеют правильное значение для senderId или receiverId, ваш запрос должен фильтровать одно из этих полей тоже. Недостаточно просто гарантировать, что threadId принадлежит разрешенному пользователю. Для этого потребуется, чтобы Firestore прочитал все документы, чтобы убедиться, что они соответствуют вашим правилам безопасности, чего он никогда не сможет сделать в масштабе.

Так что ваш «обходной путь» на самом деле является правильным решением для этого. В качестве альтернативы вы можете рассмотреть возможность сохранения каждого потока в отдельной коллекции, чтобы вы могли защитить доступ на уровне коллекции и обойти условия.

...