Mengapa pengguna baru diizinkan membuat tabel?

41

Saya bertanya-tanya mengapa pengguna yang baru dibuat diizinkan untuk membuat tabel setelah terhubung ke database. Saya memiliki satu database, 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)

Sejauh ini baik. Sekarang saya membuat pengguna:

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

Baik. Ketika saya mencoba terhubung ke database, pengguna tidak diizinkan untuk melakukannya:

$ 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.

Ini yang saya harapkan. Sekarang hal-hal aneh dimulai. Saya memberikan pengguna 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)

Dan tanpa hibah lebih lanjut, pengguna diizinkan untuk membuat tabel:

$ 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)

Saya berharap bahwa pengguna tidak diizinkan untuk melakukan apa pun sebelum saya secara eksplisit melakukannya GRANT USAGEpada skema dan kemudian GRANT SELECTpada tabel.

Di mana kesalahan saya? Apa yang saya lakukan salah? Bagaimana saya bisa mencapai apa yang saya inginkan (bahwa pengguna baru tidak diizinkan melakukan apa pun sebelum secara eksplisit memberinya hak yang sesuai.

Saya tersesat, dan bantuan Anda sangat dihargai :)

EDIT Mengikuti saran dari @ daniel-verite, saya sekarang membatalkan semua segera setelah membuat database. Dietrich pengguna tidak diizinkan membuat tabel lagi. Baik. TETAPI : Sekarang, juga pemilik basis data, project2 , tidak diperbolehkan membuat tabel. Bahkan setelah mengeluarkan GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2dan GRANT ALL PRIVILEGES ON SCHEMA public TO project2, saya mendapatkan galat ERROR: tidak ada skema yang dipilih untuk dibuat , dan ketika saya mencoba secara khusus CREATE TABLE public.WHATEVER ();, saya mendapatkan ERROR: izin ditolak untuk skema publik . Apa yang saya lakukan salah?

andreas-h
sumber

Jawaban:

38

Saat Anda membuat database baru, peran apa pun diizinkan untuk membuat objek dalam publicskema. Untuk menghapus kemungkinan ini, Anda dapat mengeluarkan segera setelah pembuatan database:

REVOKE ALL ON schema public FROM public;

Sunting: setelah perintah di atas, hanya superuser yang dapat membuat objek baru di dalam publicskema, yang tidak praktis. Dengan asumsi non-superuser foo_userharus diberikan hak istimewa ini, ini harus dilakukan dengan:

GRANT ALL ON schema public TO foo_user;

Untuk mengetahui apa ALLartinya bagi suatu skema, kita harus merujuk pada GRANT dalam dokumen , (dalam PG 9.2 ada tidak kurang dari 14 bentuk pernyataan GRANT yang berlaku untuk hal-hal yang berbeda ...). Tampaknya untuk skema artinya CREATEdan USAGE.

Di sisi lain, GRANT ALL PRIVILEGES ON DATABASE...akan memberikan CONNECTdan CREATEdan TEMP, tetapi CREATEdalam konteks ini berhubungan dengan skema, bukan tabel permanen.

Mengenai kesalahan ini:, ERROR: no schema has been selected to create interjadi ketika mencoba membuat objek tanpa kualifikasi skema (seperti pada create table foo(...)) sementara tidak memiliki izin untuk membuatnya dalam skema apa pun dari search_path.

Daniel Vérité
sumber
berfungsi :) Tapi saya masih belum mengerti: Saya sudah mencoba REVOKE ALL ON DATABASE project2_core FROM PUBLIC;. mengapa ini tidak berpengaruh?
andreas-h
mhh sekarang pemilik basis data tidak diperbolehkan CREATE TABLElagi. lihat hasil edit saya di atas.
andreas-h
@ andreas-h: edit jawaban dengan lebih detail
Daniel Vérité
Mengenai kesalahan, itu dapat dengan mudah direproduksi dengan mengeluarkan perintah dari pertanyaan dan REVOKE Anda dalam urutan :)
dezso
@ DanielVérité Saya telah menguraikan konsep di balik ini dalam jawaban baru untuk melengkapi Anda. Cek kewarasan akan dihargai.
Craig Ringer
19

Hal penting untuk dipahami di sini adalah bahwa hak istimewa tidak bersifat heirachical dan tidak diwarisi dari benda yang mengandung . ALLberarti semua hak istimewa untuk objek ini tidak semua hak istimewa untuk objek ini dan semua objek yang ada .

Ketika Anda memberikan ALLpada database, Anda memberi CREATE, CONNECT, TEMP. Ini adalah tindakan pada objek database itu sendiri:

  • CONNECT: Hubungkan ke DB
  • CREATE: Buat skema ( bukan tabel)
  • TEMP: Membuat objek sementara, termasuk tetapi tidak terbatas pada tabel temp

Sekarang, setiap database PostgreSQL secara default memiliki publicskema yang dibuat ketika database dibuat. Skema ini memiliki semua hak yang diberikan kepada peran public, di mana setiap orang secara implisit menjadi anggota. Untuk suatu skema, ALLberarti CREATE, USAGE:

  • CREATE: Membuat objek (termasuk tabel) dalam skema ini
  • USAGE: Daftar objek dalam skema dan akses jika izin mereka memungkinkan

Jika Anda tidak menentukan skema untuk membuat objek seperti tabel di, mesin database menggunakan search_path, dan secara default publicskema pertama pada search_pathsehingga tabel dibuat di sana. Setiap orang memiliki hak untuk publicsecara default, sehingga pembuatannya diperbolehkan. Hak-hak pengguna pada database tidak relevan pada saat ini, karena pengguna tidak mencoba melakukan apa pun untuk objek database itu sendiri, hanya skema di dalamnya.

Tidak masalah bahwa Anda belum memberikan hak apa pun kepada pengguna selain memberikan CONNECTpada basis data, karena publicskema tersebut memungkinkan semua pengguna untuk membuat tabel di dalamnya secara default. Daniel sudah menjelaskan cara mencabut hak itu jika diinginkan.

Jika Anda ingin mendelegasikan setiap hak secara eksplisit, cabut semua dari publik, atau cukup jatuhkan skema publik. Anda dapat membuat database template baru dengan perubahan ini diterapkan jika Anda mau. Bergantian Anda dapat menerapkannya template1, tetapi itu kemungkinan akan merusak banyak kode pihak ke-3 yang menganggap publicada dan dapat ditulisi.


Ini mungkin lebih masuk akal jika Anda melihat analogi sistem file.

Jika saya memiliki struktur direktori (mode disederhanakan untuk hanya menampilkan mode yang berlaku untuk pengguna saat ini):

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

maka saya tidak dapat membuat apa pun di dalam /dir1, karena saya tidak memiliki izin menulis. Jadi jika saya touch /dir1/somefilesaya akan mendapatkan izin ditolak kesalahan.

Namun, saya lakukan memiliki izin untuk melihat ke dalam /dir1dan akses yang terkandung file dan direktori, termasuk /dir1/dir2. Saya sudah menulis izin dir2. Jadi touch /dir1/dir2/somefileakan berhasil , meskipun saya tidak punya izin tertulis untuk dir1.

Hal yang sama dengan database dan skema.

Craig Ringer
sumber
7

Jika Anda hanya ingin mencegah pengguna baru membuat tabel, Anda perlu menjalankan perintah berikut:

REVOKE CREATE ON SCHEMA public FROM public;

Jika Anda REVOKE ALL(seperti jawaban lain menyarankan), Anda juga akan mencegah pengguna memiliki USAGEizin. USAGEberarti bahwa pengguna dapat menggunakan izin yang diberikan kepada mereka, jadi jika Anda menghapusnya maka pengguna Anda tidak akan dapat membuat daftar atau mengakses tabel yang mereka memiliki akses.

Atau, Anda juga bisa REVOKE CREATEuntuk pengguna tertentu:

REVOKE CREATE ON schema public FROM myuser;

Lihat juga: Cara membuat pengguna hanya-baca dengan PostgreSQL .

Adrian Macneil
sumber