Почему новому пользователю разрешено создавать таблицы?

41

Мне интересно, почему вновь созданному пользователю разрешено создавать таблицу после подключения к базе данных. У меня есть одна база данных project2_core:

postgres=# \l
                                          List of databases
     Name      |    Owner     | Encoding  |   Collate   |    Ctype    |       Access privileges       
---------------+--------------+-----------+-------------+-------------+-------------------------------
 postgres      | postgres     | SQL_ASCII | C           | C           | 
 project2_core | atm_project2 | UTF8      | de_DE.UTF-8 | de_DE.UTF-8 | project2=CTc/project2
 template0     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
 template1     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
(5 rows)

Все идет нормально. Теперь я создаю пользователя:

postgres=# CREATE ROLE dietrich ENCRYPTED PASSWORD 'md5XXX' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER

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

$ psql -h localhost -p 5432 -U dietrich -W project2_core
Password for user dietrich: 
psql: FATAL:  permission denied for database "project2_core"
DETAIL:  User does not have CONNECT privilege.

Это то, что я ожидал. Теперь начинается странное. Я предоставляю пользователю CONNECT:

postgres=# GRANT CONNECT ON DATABASE project2_core TO dietrich;
GRANT
postgres=# \l
                                          List of databases
     Name      |    Owner     | Encoding  |   Collate   |    Ctype    |       Access privileges       
---------------+--------------+-----------+-------------+-------------+-------------------------------
 postgres      | postgres     | SQL_ASCII | C           | C           | 
 project2_core | atm_project2 | UTF8      | de_DE.UTF-8 | de_DE.UTF-8 | project2=CTc/project2+
               |              |           |             |             | dietrich=c/project2
 template0     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
 template1     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
(5 rows)

И без каких-либо дополнительных разрешений, пользователь может создать таблицу:

$ psql -h localhost -p 5432 -U dietrich -W project2_core
Password for user dietrich: 
psql (9.2.3)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

project2_core=> create table adsf ();
CREATE TABLE
project2_core=> \d
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | adsf | table | dietrich
(1 row)

Я бы ожидал, что пользователю не разрешено ничего делать, прежде чем я сделаю это явно GRANT USAGEдля схемы, а затем GRANT SELECTдля таблиц.

Где моя ошибка? Что я делаю не так? Как я могу добиться того, чего хочу (чтобы новому пользователю не разрешалось ничего делать, прежде чем явно предоставить ему соответствующие права).

Я заблудился, и ваша помощь очень ценится :)

РЕДАКТИРОВАТЬ Следуя совету @ daniel-verite, теперь я отменил все сразу после создания базы данных. Пользователь dietrich больше не может создавать таблицы. Хорошо. НО : теперь владельцу базы данных project2 не разрешено создавать таблицы. Даже после выдачи GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2и GRANT ALL PRIVILEGES ON SCHEMA public TO project2я получаю ошибку ERROR: схема не была выбрана для создания , а когда я специально пытаюсь это сделать CREATE TABLE public.WHATEVER ();, я получаю ERROR: разрешение отклонено для общедоступной схемы . Что я делаю не так?

андреас-ч
источник

Ответы:

38

При создании новой базы данных любой роли разрешено создавать объекты в publicсхеме. Чтобы удалить эту возможность, вы можете выдать сразу после создания базы данных:

REVOKE ALL ON schema public FROM public;

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

GRANT ALL ON schema public TO foo_user;

Чтобы узнать, что ALLозначает для схемы, мы должны обратиться к GRANT в документе (в PG 9.2 есть не менее 14 форм операторов GRANT, которые применяются к разным вещам ...). Похоже, что для схемы это означает CREATEи USAGE.

С другой стороны, GRANT ALL PRIVILEGES ON DATABASE...предоставит CONNECTи CREATEи TEMP, но CREATEв этом контексте относится к схемам, а не к постоянным таблицам.

Что касается этой ошибки:, ERROR: no schema has been selected to create inэто происходит при попытке создать объект без квалификации схемы (как в create table foo(...)), но при этом отсутствует разрешение на его создание в любой схеме search_path.

Даниэль Верите
источник
работает :) Но я до сих пор не понимаю: я уже пробовал REVOKE ALL ON DATABASE project2_core FROM PUBLIC;. почему это никак не отразилось?
Андреас-ч
MHH. Теперь владелец базы данных больше не имеет права CREATE TABLE. см. мое редактирование выше.
Андреас-ч
@ andreas-h: отредактировал ответ с более подробной информацией
Даниэль Верите
Что касается ошибки, ее можно легко воспроизвести, введя команды из вопроса и ваш REVOKE по порядку :)
dezso
@ DanielVérité Я разработал концепции этого нового ответа в дополнение к вашему. Проверка работоспособности будет оценена.
Крейг Рингер
19

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

Когда вы даете ALLна базу данных, вы даете CREATE, CONNECT, TEMP. Это действия над объектом базы данных сами по себе:

  • CONNECT: Подключиться к БД
  • CREATE: Создать схему ( не таблицу)
  • TEMP: Создание временных объектов, в том числе временных таблиц

Теперь каждая база данных PostgreSQL по умолчанию имеет publicсхему, которая создается при ее создании. Эта схема имеет все права, предоставленные роли public, членом которой является каждый. Для схемы ALLозначает CREATE, USAGE:

  • CREATE: Создание объектов (включая таблицы) в этой схеме
  • USAGE: Список объектов в схеме и доступ к ним, если позволяют их разрешения

Если вы не укажете схему для создания объекта, подобного таблице, ядро ​​базы данных будет использовать search_path, и по умолчанию publicсхема будет первой, search_pathпоэтому таблица создается там. Каждый имеет права publicпо умолчанию, поэтому создание разрешено. Права пользователей на базу данных на данном этапе не имеют значения, так как пользователь не пытается ничего сделать с самим объектом базы данных, а только внутри него.

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

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


Это может иметь больше смысла, если вы посмотрите на аналогию с файловой системой.

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

/dir1           mode=r-x
/dir1/dir2      mode=rwx

тогда я не могу ничего создать внутри /dir1, потому что у меня нет разрешения на запись. Так что, если я touch /dir1/somefileполучу разрешение отказано в ошибке.

Тем не менее, у меня есть разрешение на просмотр /dir1и доступ к файлам и каталогам, в том числе /dir1/dir2. У меня есть разрешение на запись dir2. Так touch /dir1/dir2/somefileбудет иметь успех , даже если у меня нет разрешения на запись dir1.

То же самое с базами данных и схемами.

Крейг Рингер
источник
7

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

REVOKE CREATE ON SCHEMA public FROM public;

Если вы REVOKE ALL(как подсказывают другие ответы) вы также запретите пользователям иметь USAGEразрешения. USAGEозначает, что пользователи могут использовать назначенные им разрешения, поэтому, если вы удалите их, ваши пользователи не смогут просматривать или получать доступ к таблицам, к которым у них есть доступ.

В качестве альтернативы, вы могли бы также REVOKE CREATEдля конкретного пользователя:

REVOKE CREATE ON schema public FROM myuser;

Смотрите также: Как создать пользователя только для чтения с PostgreSQL .

Адриан Макнейл
источник