Правило базы данных "Поймай все остальное" в Firebase

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

Скажи, что я хочу вести учет продуктов с произвольными названиями. Каждый продукт должен содержать price, но больше ничего не разрешено.

Мой наивный подход был добавить .validate правила для продуктов, требующих, чтобы newData содержал price ребенок, явно предоставляющий доступ на запись к price узел, а затем удаляя все доступ $other узел (что-то вроде предложения по умолчанию в операторе switch):

{
    "rules": {
        "$product": {
            ".read": true,
            ".write": true,
            ".validate": "newData.hasChildren(['price'])",
            "price": {
                ".write": true,
                ".validate": "newData.isNumber()"
            },
            "$other": {
                ".read.": false,
                ".write": false,
            }
        }
    }
}

Это не работает. Добавление нового продукта с {"price": 1234, "foo": "bar"} все еще будет принят Однако, если я добавлю ".validate": false Правило для $otherвместо этого ничего не принимается (например, {"price": 1234} не допускается). (Я сделал это неправильно, как-то.)

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

1 ответ

Решение

Вы попали в несколько общих ям безопасности Firebase здесь. Наиболее распространенным является то, что разрешение распространяется каскадно: как только вы предоставили разрешение на чтение или запись на определенном уровне дерева, вы не можете отобрать это разрешение на более низком уровне.

Это означает, что эти правила неэффективны (поскольку вы уже предоставили чтение / запись на один уровень выше):

"$other": {
    ".read.": false,
    ".write": false,
}

Чтобы решить проблему, вы должны понимать, что .validate правила различны: данные считаются действительными только при соблюдении всех правил проверки. Таким образом, вы можете отклонить $other данные с правилами валидации:

{
    "rules": {
        "$product": {
            ".read": true,
            ".write": true,
            ".validate": "newData.hasChildren(['price'])",
            "price": {
                ".validate": "newData.isNumber()"
            },
            "$other": {
                ".validate": false
            }
        }
    }
}
Другие вопросы по тегам