CREATE POLICY — 為表定義新的行級安全策略
CREATE POLICYname
ONtable_name
[ AS { PERMISSIVE | RESTRICTIVE } ] [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] [ TO {role_name
| PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...] ] [ USING (using_expression
) ] [ WITH CHECK (check_expression
) ]
CREATE POLICY 命令為表定義一個新的行級安全策略。請注意,為了使建立的策略生效,必須在表上啟用行級安全(使用 ALTER TABLE ... ENABLE ROW LEVEL SECURITY)。
策略授予匹配相關策略表示式的行的 select、insert、update 或 delete 許可權。現有錶行根據 USING 中指定的表示式進行檢查,而透過 INSERT 或 UPDATE 將要建立的新行根據 WITH CHECK 中指定的表示式進行檢查。當 USING 表示式對給定行返回 true 時,該行對使用者可見;如果返回 false 或 null,則該行不可見。當 WITH CHECK 表示式對一行返回 true 時,該行將被插入或更新;如果返回 false 或 null,則會發生錯誤。
對於 INSERT、UPDATE 和 MERGE 語句,WITH CHECK 表示式在 BEFORE 觸發器觸發後、在任何實際資料修改發生之前強制執行。因此,BEFORE ROW 觸發器可能會修改要插入的資料,從而影響安全策略檢查的結果。WITH CHECK 表示式在所有其他約束之前強制執行。
策略名稱是按表劃分的。因此,一個策略名稱可以用於許多不同的表,並且每個表都可以有一個適合該表的定義。
策略可以應用於特定命令或特定角色。新建立策略的預設設定是應用於所有命令和角色,除非另有說明。多個策略可能會應用於單個命令;有關更多詳細資訊,請參閱下文。表 300 “按命令型別應用的策略” 總結了不同型別的策略如何應用於特定命令。
對於可以同時具有 USING 和 WITH CHECK 表示式(ALL 和 UPDATE)的策略,如果未定義 WITH CHECK 表示式,則 USING 表示式將同時用於確定哪些行可見(普通 USING 情況)和哪些新行將被允許新增(WITH CHECK 情況)。
如果表上啟用了行級安全,但不存在適用的策略,則假定存在“預設拒絕”策略,因此沒有任何行可見或可更新。
name
要建立的策略的名稱。此名稱必須與該表上任何其他策略的名稱不同。
table_name
策略適用的表(可選地指定模式)的名稱。
PERMISSIVE
指定該策略是作為允許策略建立的。所有適用於給定查詢的允許策略將使用布林“OR”運算子組合在一起。透過建立允許策略,管理員可以增加可訪問記錄的集合。策略預設是允許的。
RESTRICTIVE
指定該策略是作為限制策略建立的。所有適用於給定查詢的限制策略將使用布林“AND”運算子組合在一起。透過建立限制策略,管理員可以減少可訪問記錄的集合,因為必須透過所有限制策略才能訪問每個記錄。
請注意,在可以使用限制策略來減少訪問之前,至少需要有一個允許策略來授予對記錄的訪問許可權。如果只有限制策略存在,則沒有任何記錄可訪問。當存在允許策略和限制策略的混合時,只有在至少一個允許策略透過且所有限制策略都透過的情況下,記錄才可訪問。
command
策略適用的命令。有效選項為 ALL、SELECT、INSERT、UPDATE 和 DELETE。ALL 是預設值。有關這些如何應用的具體資訊,請參閱下文。
role_name
策略適用的角色。預設是 PUBLIC,它會將策略應用於所有角色。
using_expression
AnySQL條件表示式(返回 boolean)。條件表示式不能包含任何聚合或視窗函式。如果啟用了行級安全,此表示式將新增到引用表的查詢中。返回 true 的行將可見。任何返回 false 或 null 的行將對使用者不可見(在 SELECT 中),並且不可用於修改(在 UPDATE 或 DELETE 中)。這些行將被靜默忽略;不報告錯誤。
check_expression
AnySQL條件表示式(返回 boolean)。條件表示式不能包含任何聚合或視窗函式。如果啟用了行級安全,此表示式將在針對表的 INSERT 和 UPDATE 查詢中使用。只允許表示式評估為 true 的行。如果表示式對於插入的任何記錄或更新產生的任何記錄評估為 false 或 null,則會引發錯誤。請注意,check_expression 是針對行的提議新內容進行評估的,而不是針對原始內容。
ALL
#將 ALL 用於策略意味著它將適用於所有命令,無論命令型別如何。如果存在 ALL 策略並且存在更具體的策略,則將應用 ALL 策略和更具體的策略(或策略)。此外,ALL 策略將同時應用於查詢的選擇側和修改側,如果只定義了 USING 表示式,則在兩種情況下都使用 USING 表示式。
例如,如果發出 UPDATE 命令,則 ALL 策略將同時應用於 UPDATE 可以選擇哪些行進行更新(應用 USING 表示式),以及應用於結果更新的行,以檢查它們是否被允許新增到表中(如果定義了,則應用 WITH CHECK 表示式,否則應用 USING 表示式)。如果 INSERT 或 UPDATE 命令嘗試將不透過 ALL 策略的 WITH CHECK 表示式的行新增到表中,則整個命令將被中止。
SELECT
#將 SELECT 用於策略意味著它將應用於 SELECT 查詢以及在需要對策略定義的關聯物件進行 SELECT 許可權時。結果是,在 SELECT 查詢期間,只有透過 SELECT 策略的關聯物件中的記錄才會被返回,並且需要 SELECT 許可權的查詢(如 UPDATE)也將只看到允許透過 SELECT 策略的記錄。SELECT 策略不能有 WITH CHECK 表示式,因為它只適用於檢索關聯物件的記錄的情況。
INSERT
#將 INSERT 用於策略意味著它將應用於 INSERT 命令和包含 INSERT 操作的 MERGE 命令。插入不透過此策略的行將導致策略違反錯誤,並且整個 INSERT 命令將被中止。INSERT 策略不能有 USING 表示式,因為它只適用於向關聯物件新增記錄的情況。
請注意,帶有 ON CONFLICT DO UPDATE 的 INSERT 只為由 INSERT 路徑追加到關聯物件的行檢查 INSERT 策略的 WITH CHECK 表示式。
UPDATE
#將 UPDATE 用於策略意味著它將應用於 UPDATE、SELECT FOR UPDATE 和 SELECT FOR SHARE 命令,以及 INSERT 命令的輔助 ON CONFLICT DO UPDATE 子句。包含 UPDATE 操作的 MERGE 命令也會受到影響。由於 UPDATE 涉及檢索現有記錄並用修改後的新記錄替換它,因此 UPDATE 策略同時接受 USING 表示式和 WITH CHECK 表示式。USING 表示式確定 UPDATE 命令將看到哪些記錄進行操作,而 WITH CHECK 表示式定義了哪些修改後的行允許寫回關聯物件。
任何更新值不透過 WITH CHECK 表示式的行都將導致錯誤,並且整個命令將被中止。如果只指定了 USING 子句,則該子句將同時用於 USING 和 WITH CHECK 情況。
通常,UPDATE 命令還需要從被更新的關聯物件中的列讀取資料(例如,在 WHERE 子句或 RETURNING 子句中,或在 SET 子句的右側表示式中)。在這種情況下,還需要對被更新的關聯物件具有 SELECT 許可權,並且除了 UPDATE 策略之外,還將應用適當的 SELECT 或 ALL 策略。因此,使用者必須透過 SELECT 或 ALL 策略訪問要更新的行(們),同時透過 UPDATE 或 ALL 策略獲得更新行(們)的許可權。
當 INSERT 命令具有輔助 ON CONFLICT DO UPDATE 子句時,如果採取 UPDATE 路徑,則首先根據任何 UPDATE 策略的 USING 表示式檢查要更新的行,然後根據 WITH CHECK 表示式檢查新更新的行。但請注意,與獨立的 UPDATE 命令不同,如果現有行不透過 USING 表示式,則會引發錯誤(UPDATE 路徑將**絕不**被靜默跳過)。
DELETE
#將 DELETE 用於策略意味著它將應用於 DELETE 命令。只有透過此策略的行才能被 DELETE 命令看到。可能存在透過 SELECT 可見但不能刪除的行,如果它們不透過 DELETE 策略的 USING 表示式。
在大多數情況下,DELETE 命令還需要從其刪除資料的關聯物件中的列讀取資料(例如,在 WHERE 子句或 RETURNING 子句中)。在這種情況下,還需要對關聯物件具有 SELECT 許可權,並且除了 DELETE 策略之外,還將應用適當的 SELECT 或 ALL 策略。因此,使用者必須透過 SELECT 或 ALL 策略訪問要刪除的行(們),同時透過 DELETE 或 ALL 策略獲得刪除行(們)的許可權。
DELETE 策略不能有 WITH CHECK 表示式,因為它只適用於從關聯物件中刪除記錄的情況,因此沒有要檢查的新行。
表 300. 按命令型別應用的策略
命令 | SELECT/ALL 策略 |
INSERT/ALL 策略 |
UPDATE/ALL 策略 |
DELETE/ALL 策略 |
|
---|---|---|---|---|---|
USING 表示式 |
WITH CHECK 表示式 |
USING 表示式 |
WITH CHECK 表示式 |
USING 表示式 |
|
SELECT |
現有行 | — | — | — | — |
SELECT FOR UPDATE/SHARE |
現有行 | — | 現有行 | — | — |
INSERT / MERGE ... THEN INSERT |
— | 新行 | — | — | — |
INSERT ... RETURNING |
新行 [a] | 新行 | — | — | — |
UPDATE / MERGE ... THEN UPDATE |
現有行和新行 [a] | — | 現有行 | 新行 | — |
DELETE |
現有行 [a] | — | — | — | 現有行 |
ON CONFLICT DO UPDATE |
現有行和新行 | — | 現有行 | 新行 | — |
[a] 如果需要對現有行或新行進行讀取訪問(例如,引用關聯物件中列的 WHERE 或 RETURNING 子句)。 |
當不同命令型別的多個策略應用於同一命令時(例如,應用於 UPDATE 命令的 SELECT 和 UPDATE 策略),使用者必須同時擁有這兩種型別的許可權(例如,從關聯物件中選擇行的許可權以及更新它們的許可權)。因此,一種型別的策略的表示式與另一種型別的策略的表示式結合使用 AND 運算子。
當同一命令的同一命令型別的多個策略適用時,至少必須有一個 PERMISSIVE 策略授予對關聯物件的訪問許可權,並且所有 RESTRICTIVE 策略都必須透過。因此,所有 PERMISSIVE 策略表示式使用 OR 組合,所有 RESTRICTIVE 策略表示式使用 AND 組合,並且結果使用 AND 組合。如果沒有 PERMISSIVE 策略,則拒絕訪問。
請注意,為了組合多個策略,ALL 策略將被視為具有與正在應用的另一類策略相同的型別。
例如,在需要 SELECT 和 UPDATE 許可權的 UPDATE 命令中,如果每種型別的多個策略適用,它們將按如下方式組合:
expression
from RESTRICTIVE SELECT/ALL policy 1 ANDexpression
from RESTRICTIVE SELECT/ALL policy 2 AND ... AND (expression
from PERMISSIVE SELECT/ALL policy 1 ORexpression
from PERMISSIVE SELECT/ALL policy 2 OR ... ) ANDexpression
from RESTRICTIVE UPDATE/ALL policy 1 ANDexpression
from RESTRICTIVE UPDATE/ALL policy 2 AND ... AND (expression
from PERMISSIVE UPDATE/ALL policy 1 ORexpression
from PERMISSIVE UPDATE/ALL policy 2 OR ... )
您必須是表的擁有者才能為其建立或更改策略。
雖然策略將應用於對資料庫中表的顯式查詢,但當系統執行內部參照完整性檢查或驗證約束時,它們不會被應用。這意味著存在確定給定值是否存在的間接方法。一個例子是嘗試將重複值插入到作為主鍵或具有唯一約束的列中。如果插入失敗,使用者可以推斷該值已存在。(此示例假設使用者有權插入他們無權檢視的記錄。)另一個例子是使用者被允許插入引用另一個(否則隱藏的)表的表。可以透過使用者在引用表中插入值來確定是否存在,如果成功則表示值存在於被引用表中。這些問題可以透過仔細制定策略來解決,以防止使用者能夠插入、刪除或更新任何可能指示他們無法檢視的值的記錄,或者透過使用生成值(例如,代理鍵)而不是具有外部含義的鍵。
通常,系統會在使用者查詢中出現的條件之前強制執行使用安全策略施加的過濾條件,以防止將受保護的資料意外暴露給可能不可信的使用者定義函式。但是,被系統(或系統管理員)標記為 LEAKPROOF 的函式和運算子可能會在策略表示式之前進行評估,因為它們被假定為可信。
由於策略表示式直接新增到使用者的查詢中,因此它們將以執行整個查詢的使用者許可權執行。因此,使用給定策略的使用者必須能夠訪問表示式中引用的任何表或函式,否則在嘗試查詢啟用了行級安全功能的表時,他們將收到許可權被拒絕的錯誤。但這不會改變檢視的工作方式。與普通查詢和檢視一樣,對檢視引用的表進行許可權檢查和策略將使用檢視擁有者的許可權和適用於檢視擁有者的任何策略,除非檢視是使用 security_invoker 選項定義的(請參閱 CREATE VIEW)。
MERGE 沒有單獨的策略。相反,在執行 MERGE 時,將根據所執行的操作來應用為 SELECT、INSERT、UPDATE 和 DELETE 定義的策略。
更多討論和實際示例可在第 5.9 節“行安全策略”中找到。
CREATE POLICY 是 PostgreSQL 的擴充套件。
如果您在文件中發現任何不正確、與您的實際使用經驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。