由於 PostgreSQL 規則系統會重寫查詢,因此會存取原始查詢中使用的表格/檢視表之外的其他表格/檢視表。當使用更新規則時,這可能包括對表格的寫入權限。
重寫規則沒有單獨的所有者。 關係(表格或檢視表)的所有者會自動成為為其定義的重寫規則的所有者。PostgreSQL 規則系統會更改預設存取控制系統的行為。除了與安全調用者檢視相關聯的 SELECT
規則(請參閱CREATE VIEW
)之外,由於規則而使用的所有關係都會根據規則所有者的權限進行檢查,而不是調用規則的使用者。這表示,除了安全調用者檢視之外,使用者只需要對查詢中明確命名的表格/檢視表擁有必要的權限。
例如:使用者有一個電話號碼清單,其中一些是私人的,另一些是辦公室助理感興趣的。 使用者可以建構以下內容
CREATE TABLE phone_data (person text, phone text, private boolean); CREATE VIEW phone_number AS SELECT person, CASE WHEN NOT private THEN phone END AS phone FROM phone_data; GRANT SELECT ON phone_number TO assistant;
除了該使用者(和資料庫超級使用者)之外,沒有人可以存取 phone_data
表格。 但由於 GRANT
,助理可以在 phone_number
檢視表上執行 SELECT
。 規則系統會將來自 phone_number
的 SELECT
重寫為來自 phone_data
的 SELECT
。 由於使用者是 phone_number
的所有者,因此也是規則的所有者,因此現在會根據使用者的權限檢查對 phone_data
的讀取權限,並且允許查詢。 也會執行存取 phone_number
的檢查,但這是針對調用使用者進行的,因此除了使用者和助理之外,沒有人可以使用它。
權限會逐條規則檢查。 因此,目前助理是唯一可以看到公共電話號碼的人。 但助理可以設定另一個檢視表,並授予公眾對該檢視表的存取權。 然後,任何人都可以透過助理的檢視表看到 phone_number
資料。 助理無法做的是建立直接存取 phone_data
的檢視表。 (實際上助理可以,但它不會運作,因為每次存取都會在權限檢查期間被拒絕。)一旦使用者注意到助理打開了他們的 phone_number
檢視表,使用者就可以撤銷助理的存取權。 立即,對助理檢視表的任何存取都會失敗。
有人可能會認為這種逐條規則檢查是一個安全漏洞,但事實並非如此。 但如果它沒有以這種方式運作,助理可以建立一個與 phone_number
具有相同欄位的表格,並每天將資料複製到那裡一次。 然後它就是助理自己的資料,助理可以授予他們想要的任何人的存取權。GRANT
指令表示,“我相信你”。 如果您信任的人做了上述事情,就該仔細考慮一下,然後使用 REVOKE
。
請注意,雖然可以使用上述技術,透過檢視表來隱藏某些欄位的內容,但除非設定了 security_barrier
旗標,否則它們無法可靠地隱藏未顯示列中的資料。 例如,以下檢視表是不安全的
CREATE VIEW phone_number AS SELECT person, phone FROM phone_data WHERE phone NOT LIKE '412%';
這個檢視表似乎是安全的,因為規則系統會將來自 phone_number
的任何 SELECT
重寫為來自 phone_data
的 SELECT
,並增加僅需要 phone
不以 412 開頭的條目的限定條件。 但如果使用者可以建立自己的函式,則不難說服規劃器在 NOT LIKE
運算式之前執行使用者定義的函式。 例如
CREATE FUNCTION tricky(text, text) RETURNS bool AS $$ BEGIN RAISE NOTICE '% => %', $1, $2; RETURN true; END; $$ LANGUAGE plpgsql COST 0.0000000000000000000001; SELECT * FROM phone_number WHERE tricky(person, phone);
在 phone_data
資料表中,每個人和電話號碼都會被列印成 NOTICE
,因為查詢規劃器會選擇先執行成本較低的 tricky
函式,再執行成本較高的 NOT LIKE
。即使使用者被禁止定義新的函式,內建函式也可以用在類似的攻擊中。(例如,大多數轉換函式會在它們產生的錯誤訊息中包含輸入值。)
類似的考量也適用於更新規則。在前一節的範例中,範例資料庫中的資料表擁有者可以將 shoelace
檢視表的 SELECT
、INSERT
、UPDATE
和 DELETE
權限授予其他人,但僅授予 shoelace_log
的 SELECT
權限。寫入日誌條目的規則動作仍然會成功執行,而其他使用者可以看到日誌條目。但他們無法建立假的條目,也無法操縱或移除現有的條目。在這種情況下,沒有可能透過說服查詢規劃器更改操作順序來顛覆規則,因為唯一引用 shoelace_log
的規則是不限定的 INSERT
。在更複雜的情況下,這可能不成立。
當檢視表需要提供列層級安全性時,應將 security_barrier
屬性套用到該檢視表。這可以防止惡意選擇的函式和運算子在檢視表完成其工作之前,從列中傳遞值。例如,如果以上所示的檢視表是這樣建立的,它將是安全的
CREATE VIEW phone_number WITH (security_barrier) AS SELECT person, phone FROM phone_data WHERE phone NOT LIKE '412%';
使用 security_barrier
建立的檢視表,效能可能遠比未使用此選項建立的檢視表差。一般來說,沒有辦法避免這種情況:如果最快的可能計畫可能會危及安全性,則必須拒絕它。因此,預設情況下不啟用此選項。
當處理沒有副作用的函式時,查詢規劃器有更大的彈性。此類函式稱為 LEAKPROOF
,包括許多簡單、常用的運算子,例如許多等式運算子。查詢規劃器可以安全地允許在查詢執行過程中的任何時間點評估這些函式,因為在使用者不可見的列上調用它們不會洩漏有關未見列的任何資訊。此外,不帶引數或未從安全屏障檢視表傳遞任何引數的函式,不必標記為 LEAKPROOF
即可被下推,因為它們永遠不會從檢視表接收資料。相反地,根據收到的引數值可能拋出錯誤的函式(例如在發生溢位或除以零時拋出錯誤的函式)不是防洩漏的,如果在安全檢視表的列篩選器之前應用,可能會提供有關未見列的重大資訊。
重要的是要理解,即使使用 security_barrier
選項建立的檢視表,也僅在有限的意義上是安全的,即不可見 Tuple 的內容不會傳遞給可能不安全的函式。使用者很可能還有其他方法可以推斷未見的資料;例如,他們可以使用 EXPLAIN
查看查詢計畫,或測量針對檢視表執行查詢的時間。惡意攻擊者或許能夠推斷出有關未見資料量的一些資訊,甚至獲得有關資料分佈或最常見值的一些資訊(因為這些事情可能會影響計畫的執行時間;或者甚至會反映在最佳化器的統計資料中,進而影響計畫的選擇)。如果這些類型的「隱蔽通道」攻擊令人擔憂,則最好不要授予任何對資料的存取權。
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步說明的地方,請使用此表單來報告文件問題。