ทำไมผู้ใช้ใหม่ได้รับอนุญาตให้สร้างตาราง?


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ฉันได้รับข้อผิดพลาดข้อผิดพลาด: ไม่มีสคีได้รับเลือกที่จะสร้างในและเมื่อฉันเฉพาะพยายามที่จะCREATE TABLE public.WHATEVER ();ฉันได้รับข้อผิดพลาด: อนุญาตปฏิเสธสำหรับสคีสาธารณะ ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


38

เมื่อคุณสร้างฐานข้อมูลใหม่บทบาทใด ๆ ที่ได้รับอนุญาตให้สร้างวัตถุในpublicสคีมา หากต้องการลบความเป็นไปได้นี้คุณอาจออกโดยทันทีหลังจากการสร้างฐานข้อมูล:

REVOKE ALL ON schema public FROM public;

แก้ไข: หลังจากคำสั่งด้านบนมีเพียง superuser เท่านั้นที่สามารถสร้างวัตถุใหม่ภายในpublicสคีมาซึ่งไม่สามารถใช้งานได้ สมมติว่าผู้ที่ไม่ใช่ผู้ใช้ระดับสูงfoo_userควรได้รับสิทธิ์นี้สิ่งนี้ควรทำด้วย:

GRANT ALL ON schema public TO foo_user;

หากต้องการทราบALLว่าสคีมานั้นหมายถึงอะไรเราต้องอ้างถึงGRANT ในเอกสาร (ใน PG 9.2 มีคำสั่ง GRANT ไม่น้อยกว่า 14 รูปแบบที่ใช้กับสิ่งต่าง ๆ ... ) ปรากฏว่าสำหรับสคีมามันหมายและCREATEUSAGE

ในทางกลับกัน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;ฉันพยายามแล้ว ทำไมสิ่งนี้ถึงไม่มีผลอะไรเลย?
andreas-h

mhh ตอนนี้เจ้าของฐานข้อมูลไม่ได้รับอนุญาตCREATE TABLEอีกต่อไป ดูการแก้ไขของฉันด้านบน
andreas-h

@ andreas-h: แก้ไขคำตอบด้วยรายละเอียดเพิ่มเติม
Daniel Vérité

เกี่ยวกับข้อผิดพลาดก็สามารถทำซ้ำได้อย่างง่ายดายโดยการออกคำสั่งจากคำถามและถอนของคุณเพื่อ :)
Dezso

@ DanielVéritéฉันได้อธิบายแนวคิดที่อยู่เบื้องหลังนี้ในคำตอบใหม่เพื่อเสริมความเป็นคุณ การตรวจสติจะมีค่า
Craig Ringer

19

สิ่งสำคัญที่จะเข้าใจว่านี่คือสิทธิพิเศษไม่ได้ heirachicalและจะไม่ได้รับมรดกมาจากวัตถุที่มี ALLหมายถึงสิทธิ์ทั้งหมดสำหรับวัตถุนี้ไม่ได้สิทธิ์ทั้งหมดสำหรับวัตถุนี้และวัตถุที่มีอยู่ทั้งหมด

เมื่อคุณให้กับฐานข้อมูลที่คุณกำลังอนุญาตALL CREATE, CONNECT, TEMPสิ่งเหล่านี้เป็นการกระทำบนวัตถุฐานข้อมูลของตนเอง:

  • CONNECT: เชื่อมต่อกับฐานข้อมูล
  • CREATE: สร้างสคีมา ( ไม่ใช่ตาราง)
  • TEMP: สร้างวัตถุชั่วคราวรวมถึง แต่ไม่ จำกัด เฉพาะเทมเพลตชั่วคราว

ตอนนี้แต่ละฐานข้อมูล PostgreSQL ตามค่าเริ่มต้นจะมีpublicสคีมาที่สร้างขึ้นเมื่อสร้างฐานข้อมูล สคีมานี้มีสิทธิ์ทั้งหมดที่ให้กับบทบาทpublicซึ่งทุกคนเป็นสมาชิกโดยปริยาย สำหรับสคีมาALLหมายถึงCREATE, USAGE:

  • CREATE: สร้างวัตถุ (รวมถึงตาราง) ภายในสคีมานี้
  • USAGE: รายการวัตถุในสคีมาและเข้าถึงพวกเขาหากสิทธิ์ของพวกเขาอนุญาต

หากคุณไม่ได้ระบุสคีมาเพื่อสร้างวัตถุเช่นตารางในเอ็นจิ้นฐานข้อมูลจะใช้search_pathและโดยค่าเริ่มต้นpublicสคีมาเป็นครั้งแรกsearch_pathเพื่อให้ตารางถูกสร้างขึ้นที่นั่น ทุกคนมีสิทธิ์publicตามค่าเริ่มต้นดังนั้นจึงอนุญาตให้สร้างได้ สิทธิ์ของผู้ใช้ในฐานข้อมูลไม่เกี่ยวข้องในจุดนี้เนื่องจากผู้ใช้ไม่ได้พยายามทำสิ่งใด ๆ กับวัตถุฐานข้อมูลของตนเอง แต่มีเพียงสคีมาอยู่ภายใน

ไม่สำคัญว่าคุณยังไม่ได้ให้สิทธิ์แก่ผู้ใช้นอกเหนือจากการให้สิทธิ์CONNECTในฐานข้อมูลเพราะ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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.