支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5

CREATE POLICY

CREATE POLICY — 為表格定義一個新的列層級安全策略

概要

CREATE POLICY name ON table_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 中指定的表達式進行檢查,而將通過 INSERTUPDATE 建立的新列會根據 WITH CHECK 中指定的表達式進行檢查。當 USING 表達式對於給定的列返回 true 時,該列對使用者可見;如果返回 false 或 null,則該列不可見。當 WITH CHECK 表達式對於一個列返回 true 時,該列將被插入或更新;如果返回 false 或 null,則會發生錯誤。

對於 INSERTUPDATEMERGE 語句,WITH CHECK 表達式在觸發 BEFORE 觸發器之後以及進行任何實際資料修改之前強制執行。因此,BEFORE ROW 觸發器可以修改要插入的資料,從而影響安全策略檢查的結果。WITH CHECK 表達式在任何其他約束之前強制執行。

策略名稱是按表格劃分的。因此,一個策略名稱可以用於許多不同的表格,並且每個表格都有一個適合該表格的定義。

策略可以應用於特定的命令或特定的角色。新建立的策略預設適用於所有命令和角色,除非另有說明。多個策略可能適用於單個命令;詳情請見下文。表格 297 總結了不同類型的策略如何應用於特定命令。

對於可以同時具有 USINGWITH CHECK 表達式(ALLUPDATE)的策略,如果未定義 WITH CHECK 表達式,則 USING 表達式將用於確定哪些列是可見的(通常的 USING 情況)以及允許新增哪些新列(WITH CHECK 情況)。

如果為表格啟用了列層級安全,但不存在適用的策略,則假定一個預設拒絕策略,因此任何列都不可見或不可更新。

參數

name

要建立的策略的名稱。它必須與該表格的任何其他策略的名稱不同。

table_name

策略所適用的表格的名稱(可選擇包含 schema)。

PERMISSIVE

指定將策略建立為寬鬆策略。適用於給定查詢的所有寬鬆策略將使用布林 OR 運算子組合在一起。透過建立寬鬆策略,管理員可以新增可存取的記錄集。預設情況下,策略是寬鬆的。

RESTRICTIVE

指定將策略建立為限制性策略。適用於給定查詢的所有限制性策略將使用布林 AND 運算子組合在一起。透過建立限制性策略,管理員可以減少可存取的記錄集,因為每個記錄都必須通過所有限制性策略。

請注意,至少需要一個寬鬆策略來授予對記錄的存取權限,然後才能有效地使用限制性策略來減少該存取權限。如果只有限制性策略存在,則任何記錄都無法存取。當同時存在寬鬆策略和限制性策略時,只有在至少一個寬鬆策略通過且所有限制性策略都通過的情況下,記錄才能存取。

command

策略所適用的命令。有效的選項為 ALLSELECTINSERTUPDATEDELETEALL 是預設值。請參閱下文,瞭解有關如何應用它們的詳細資訊。

role_name

策略將應用於的角色。預設值為 PUBLIC,這會將策略應用於所有角色。

using_expression

任何SQL條件表達式(回傳 boolean)。條件表達式不能包含任何聚集或視窗函數。如果啟用列層級安全性,此表達式將新增到參考該資料表的查詢。表達式回傳 true 的列將會可見。任何表達式回傳 false 或 null 的列將不會對使用者可見(在 SELECT 中),並且無法修改(在 UPDATEDELETE 中)。這些列將會被靜默地抑制;不會報告任何錯誤。

check_expression

任何SQL條件表達式(回傳 boolean)。條件表達式不能包含任何聚集或視窗函數。如果啟用列層級安全性,此表達式將用於針對資料表的 INSERTUPDATE 查詢中。只有表達式評估為 true 的列才被允許。如果對於任何插入的記錄或任何更新後的記錄,表達式評估為 false 或 null,則會拋出錯誤。請注意,check_expression 是根據建議的新列內容進行評估,而不是原始內容。

單一指令原則

ALL #

ALL 用於原則表示它將適用於所有指令,無論指令類型為何。如果存在 ALL 原則,並且存在更具體的原則,則 ALL 原則和更具體的原則都將被套用。此外,ALL 原則將同時應用於查詢的選擇端和修改端,如果僅定義了 USING 表達式,則這兩種情況都使用 USING 表達式。

例如,如果發出 UPDATE 指令,則 ALL 原則將同時適用於 UPDATE 能夠選擇要更新的列(套用 USING 表達式),以及產生的更新列,以檢查是否允許將它們新增到資料表中(套用 WITH CHECK 表達式,如果已定義,否則套用 USING 表達式)。如果 INSERTUPDATE 指令嘗試將未通過 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 UPDATEINSERT 僅針對由 INSERT 路徑附加到關係的列檢查 INSERT 原則的 WITH CHECK 表達式。

UPDATE #

UPDATE 用於原則表示它將適用於 UPDATESELECT FOR UPDATESELECT FOR SHARE 指令,以及 INSERT 指令的輔助 ON CONFLICT DO UPDATE 子句。包含 UPDATE 動作的 MERGE 指令也會受到影響。由於 UPDATE 涉及提取現有記錄並將其替換為新的修改記錄,因此 UPDATE 原則接受 USING 表達式和 WITH CHECK 表達式。USING 表達式確定 UPDATE 指令將看到哪些記錄以對其進行操作,而 WITH CHECK 表達式定義允許將哪些修改後的列儲存回關係中。

任何更新的值未通過 WITH CHECK 表達式的列將導致錯誤,並且整個指令將中止。如果僅指定了 USING 子句,則該子句將用於 USINGWITH CHECK 兩種情況。

通常,UPDATE 指令還需要讀取正在更新的關係中的列的資料(例如,在 WHERE 子句或 RETURNING 子句中,或在 SET 子句右側的表達式中)。在這種情況下,還需要對正在更新的關係具備 SELECT 權限,並且除了 UPDATE 原則之外,還會套用適當的 SELECTALL 原則。因此,除了被授予通過 UPDATEALL 原則更新列的權限之外,使用者還必須通過 SELECTALL 原則存取要更新的列。

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 策略之外,還將應用適當的 SELECTALL 策略。因此,使用者必須透過 SELECTALL 策略存取要刪除的資料列,並且還必須透過 DELETEALL 策略被授予刪除該資料列的權限。

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] 如果需要讀取現有或新資料列(例如,引用關係中欄位的 WHERERETURNING 子句)。


多個策略的應用

當多個不同命令類型的策略應用於同一個命令時(例如,應用於 UPDATE 命令的 SELECTUPDATE 策略),則使用者必須同時具有這兩種權限(例如,從關係中選擇資料列的權限以及更新它們的權限)。因此,一種策略類型的運算式會與另一種策略類型的運算式使用 AND 運算子組合在一起。

當多個相同命令類型的策略應用於同一個命令時,則必須至少有一個 PERMISSIVE 策略授予對關係的存取權,並且所有 RESTRICTIVE 策略都必須通過。因此,所有 PERMISSIVE 策略運算式都使用 OR 組合在一起,所有 RESTRICTIVE 策略運算式都使用 AND 組合在一起,並且結果使用 AND 組合在一起。如果沒有 PERMISSIVE 策略,則拒絕存取。

請注意,為了組合多個策略的目的,ALL 策略被視為與正在應用其他策略的類型相同。

例如,在需要 SELECTUPDATE 權限的 UPDATE 命令中,如果每種類型有多個適用的策略,它們將按如下方式組合

expression from RESTRICTIVE SELECT/ALL policy 1
AND
expression from RESTRICTIVE SELECT/ALL policy 2
AND
...
AND
(
  expression from PERMISSIVE SELECT/ALL policy 1
  OR
  expression from PERMISSIVE SELECT/ALL policy 2
  OR
  ...
)
AND
expression from RESTRICTIVE UPDATE/ALL policy 1
AND
expression from RESTRICTIVE UPDATE/ALL policy 2
AND
...
AND
(
  expression from PERMISSIVE UPDATE/ALL policy 1
  OR
  expression from PERMISSIVE UPDATE/ALL policy 2
  OR
  ...
)

注意事項

您必須是表格的擁有者才能建立或變更其策略。

雖然策略將應用於針對資料庫中表格的顯式查詢,但當系統執行內部參考完整性檢查或驗證約束時,不會應用它們。這意味著存在確定給定值存在的間接方法。例如,嘗試將重複的值插入到作為主鍵或具有唯一約束的欄位中。如果插入失敗,則使用者可以推斷該值已存在。(此範例假設使用者被策略允許插入他們不允許看到的記錄。)另一個範例是用戶被允許插入到引用另一個,否則隱藏的表格中。可以通過用戶將值插入到引用表格中來確定存在,其中成功表示該值存在於被引用表格中。可以通過仔細設計策略來防止用戶完全插入、刪除或更新可能指示他們無法以其他方式看到的值的記錄,或者通過使用生成的值(例如,代理鍵)代替具有外部含義的鍵來解決這些問題。

通常,系統將在使用者查詢中出現的限定條件之前,強制執行使用安全策略施加的篩選條件,以防止將受保護的資料無意中暴露給可能不可信的使用者定義函數。但是,由系統(或系統管理員)標記為 LEAKPROOF 的函數和運算子可以在策略運算式之前進行評估,因為它們被認為是可信的。

由於策略運算式直接新增到使用者的查詢中,因此它們將以執行整個查詢的使用者的權限執行。因此,使用給定策略的使用者必須能夠存取運算式中引用的任何表格或函數,否則他們在嘗試查詢已啟用資料列層級安全性的表格時只會收到權限拒絕錯誤。然而,這不會改變檢視表的工作方式。與普通查詢和檢視表一樣,檢視表引用的表格的權限檢查和策略將使用檢視表擁有者的權限和適用於檢視表擁有者的任何策略,除非使用 security_invoker 選項定義檢視表(請參閱 CREATE VIEW)。

沒有針對 MERGE 的單獨策略。相反,在執行 MERGE 時,將應用為 SELECTINSERTUPDATEDELETE 定義的策略,具體取決於執行的動作。

更多討論和實際範例可以在 第 5.9 節 中找到。

相容性

CREATE POLICY 是一個 PostgreSQL 擴充功能。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步說明的內容,請使用此表格來報告文件問題。