由於 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
。規則系統會將 SELECT
從 phone_number
重寫為從 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
就可以被下推,因為它們永遠不會從檢視接收資料。相反,根據收到的引數值可能引發錯誤的函式(例如,在溢位或除以零的情況下引發錯誤的函式)不是 leakproof 的,並且在安全檢視的行過濾器之前應用時,可能會洩露有關不可見行的重要資訊。
例如,對於安全屏障檢視(或具有行級安全策略的表)的查詢,如果 WHERE
子句中使用的運算子與索引的運算子族相關聯,但其底層函式未標記為 LEAKPROOF
,則無法選擇索引掃描。 psql 程式的 \dAo+
元命令可用於列出運算子族並確定其中哪些運算子被標記為 leakproof。
重要的是要理解,即使是使用 security_barrier
選項建立的檢視,其安全性也僅限於不可見元組的內容不會傳遞給可能不安全的函式。使用者仍然可能有其他方法來推斷不可見資料;例如,他們可以使用 EXPLAIN
檢視查詢計劃,或測量針對檢視的查詢的執行時間。惡意攻擊者可能能夠推斷出有關不可見資料量的某些資訊,甚至可能獲得有關資料分佈或最常見值的一些資訊(因為這些可能會影響計劃的執行時間;甚至,因為它們也反映在最佳化器統計資訊中,所以也會影響計劃的選擇)。如果擔心這些型別的“隱蔽通道”攻擊,最好根本不要授予對資料的任何訪問許可權。
如果您在文件中看到任何不正確、與您在使用特定功能時的體驗不符或需要進一步澄清的內容,請使用 此表格 報告文件問題。