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
),才能應用已建立的策略。
策略授予選取、插入、更新或刪除符合相關策略表達式的列的權限。現有表格列會根據 USING
中指定的表達式進行檢查,而將通過 INSERT
或 UPDATE
建立的新列會根據 WITH CHECK
中指定的表達式進行檢查。當 USING
表達式對於給定的列返回 true 時,該列對使用者可見;如果返回 false 或 null,則該列不可見。當 WITH CHECK
表達式對於一個列返回 true 時,該列將被插入或更新;如果返回 false 或 null,則會發生錯誤。
對於 INSERT
、UPDATE
和 MERGE
語句,WITH CHECK
表達式在觸發 BEFORE
觸發器之後以及進行任何實際資料修改之前強制執行。因此,BEFORE ROW
觸發器可以修改要插入的資料,從而影響安全策略檢查的結果。WITH CHECK
表達式在任何其他約束之前強制執行。
策略名稱是按表格劃分的。因此,一個策略名稱可以用於許多不同的表格,並且每個表格都有一個適合該表格的定義。
策略可以應用於特定的命令或特定的角色。新建立的策略預設適用於所有命令和角色,除非另有說明。多個策略可能適用於單個命令;詳情請見下文。表格 297 總結了不同類型的策略如何應用於特定命令。
對於可以同時具有 USING
和 WITH CHECK
表達式(ALL
和 UPDATE
)的策略,如果未定義 WITH CHECK
表達式,則 USING
表達式將用於確定哪些列是可見的(通常的 USING
情況)以及允許新增哪些新列(WITH CHECK
情況)。
如果為表格啟用了列層級安全,但不存在適用的策略,則假定一個“預設拒絕”策略,因此任何列都不可見或不可更新。
name
要建立的策略的名稱。它必須與該表格的任何其他策略的名稱不同。
table_name
策略所適用的表格的名稱(可選擇包含 schema)。
PERMISSIVE
指定將策略建立為寬鬆策略。適用於給定查詢的所有寬鬆策略將使用布林 “OR” 運算子組合在一起。透過建立寬鬆策略,管理員可以新增可存取的記錄集。預設情況下,策略是寬鬆的。
RESTRICTIVE
指定將策略建立為限制性策略。適用於給定查詢的所有限制性策略將使用布林 “AND” 運算子組合在一起。透過建立限制性策略,管理員可以減少可存取的記錄集,因為每個記錄都必須通過所有限制性策略。
請注意,至少需要一個寬鬆策略來授予對記錄的存取權限,然後才能有效地使用限制性策略來減少該存取權限。如果只有限制性策略存在,則任何記錄都無法存取。當同時存在寬鬆策略和限制性策略時,只有在至少一個寬鬆策略通過且所有限制性策略都通過的情況下,記錄才能存取。
command
策略所適用的命令。有效的選項為 ALL
、SELECT
、INSERT
、UPDATE
和 DELETE
。ALL
是預設值。請參閱下文,瞭解有關如何應用它們的詳細資訊。
role_name
策略將應用於的角色。預設值為 PUBLIC
,這會將策略應用於所有角色。
using_expression
任何SQL條件表達式(回傳 boolean
)。條件表達式不能包含任何聚集或視窗函數。如果啟用列層級安全性,此表達式將新增到參考該資料表的查詢。表達式回傳 true 的列將會可見。任何表達式回傳 false 或 null 的列將不會對使用者可見(在 SELECT
中),並且無法修改(在 UPDATE
或 DELETE
中)。這些列將會被靜默地抑制;不會報告任何錯誤。
check_expression
任何SQL條件表達式(回傳 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
原則。因此,除了被授予通過 UPDATE
或 ALL
原則更新列的權限之外,使用者還必須通過 SELECT
或 ALL
原則存取要更新的列。
當 INSERT
指令具有輔助 ON CONFLICT DO UPDATE
子句時,如果採用了 UPDATE
路徑,則首先根據任何 UPDATE
原則的 USING
表達式檢查要更新的列,然後根據 WITH CHECK
表達式檢查新的更新列。但是請注意,與獨立的 UPDATE
指令不同,如果現有列未通過 USING
表達式,則會拋出錯誤(UPDATE
路徑將永遠不會被靜默地避免)。
DELETE
#使用 DELETE
策略表示它將應用於 DELETE
命令。只有符合此策略的資料列才會被 DELETE
命令看到。如果某些資料列不符合 DELETE
策略的 USING
運算式,則它們可能透過 SELECT
可見,但無法用於刪除。
在大多數情況下,DELETE
命令也需要從它所刪除的關係中的欄位讀取資料(例如,在 WHERE
子句或 RETURNING
子句中)。在這種情況下,也需要對關係具有 SELECT
權限,並且除了 DELETE
策略之外,還將應用適當的 SELECT
或 ALL
策略。因此,使用者必須透過 SELECT
或 ALL
策略存取要刪除的資料列,並且還必須透過 DELETE
或 ALL
策略被授予刪除該資料列的權限。
DELETE
策略不能有 WITH CHECK
運算式,因為它僅適用於從關係中刪除記錄的情況,因此沒有新的資料列可以檢查。
表格 297. 依命令類型套用的策略
命令 | 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] 如果需要讀取現有或新資料列(例如,引用關係中欄位的 |
當多個不同命令類型的策略應用於同一個命令時(例如,應用於 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 擴充功能。
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步說明的內容,請使用此表格來報告文件問題。