虛擬私有資料庫 (VPD),又稱細粒度存取控制 (FGAC),自 Oracle 8i 推出。核心原理:在查詢執行時透明重寫 SQL,依安全策略函數回傳的謂詞 (Predicate) 過濾資料列。例如:
-- 原始查詢
SELECT * FROM accounts;
-- VPD 自動重寫為
SELECT * FROM accounts WHERE am_name = 'SCOTT';
策略函數根據使用者身分、權限、應用程式上下文動態產生 WHERE 子句字串。
舊版僅支援 Dynamic 政策(每次查詢皆重新執行策略函數)。10g 依謂詞結構特性引入四種新類型,大幅降低 CPU 開銷:
| 策略類型 | 適用情境 | 重新執行條件 | 範例謂詞 |
|---|---|---|---|
| DYNAMIC (預設) | 謂詞高度動態,每列每用戶皆不同 | 每次查詢、每列 | WHERE am_name = 'SCOTT' |
| CONTEXT_SENSITIVE | 謂詞靜態部分固定,動態部分源自應用程式上下文 | 應用程式上下文變更時 | WHERE balance < SYS_CONTEXT('vpdctx','maxbal') |
| SHARED_CONTEXT_SENSITIVE | 多表共用相同策略函數,上下文未變 | 跨物件查詢且上下文未變時不重跑 | 同 CONTEXT_SENSITIVE,套用於 SAVINGS/CHECKING 兩表 |
| STATIC | 謂詞完全由登入用戶決定,Session 期間不變 | 僅首次查詢執行一次,永不重跑 | WHERE cust_name = SYS_CONTEXT('vpdctx','cust_name') |
| SHARED_STATIC | 多表共用靜態策略 | 同 STATIC,跨物件共用 | 同 STATIC |
CREATE OR REPLACE FUNCTION vpd_pol_func(p_schema VARCHAR2, p_table VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN 'balance < SYS_CONTEXT(''vpdctx'', ''maxbal'')';
END;
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'SCOTT',
object_name => 'ACCOUNTS',
policy_name => 'BALANCE_LIMIT',
function_schema => 'SEC_ADMIN',
policy_function => 'VPD_POL_FUNC',
policy_type => DBMS_RLS.CONTEXT_SENSITIVE
);
END;
Session 期間若 SYS_CONTEXT('vpdctx','maxbal') 不變,函數不重跑。
Static 策略將謂詞快取於 SGA,Session 中上下文變更將 不會 觸發函數重跑,導致錯誤結果。僅在絕對確定 Session 期間上下文不變時使用(如單一資料庫帳戶對應單一租戶的託管環境)。
10g 新增 SEC_RELEVANT_COLS 與 SEC_RELEVANT_COLS_OPT 參數:
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'HR',
object_name => 'EMPLOYEES',
policy_name => 'SALARY_MASK',
function_schema => 'SEC',
policy_function => 'SALARY_POL_FUNC',
sec_relevant_cols => 'SALARY',
sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS -- 啟用列遮罩
);
END;
查詢 SELECT * FROM employees 時,無權限用戶看到 SALARY 欄為 NULL,而非整列消失。若 SELECT COUNT(*) 則不受影響。
OEM 10g 提供圖形化介面建立、編輯、啟用/停用 VPD 政策,並可直接檢視產生的謂詞與執行計畫,大幅降低維運複雜度。
Oracle 10g 透過五種策略類型、列相關策略與列遮罩,將 VPD 從「安全工具」昇級為「高效能安全框架」。正確選擇策略類型(Dynamic → Context Sensitive → Static)配合應用程式上下文設計,可在確保資料隔離的前提下將效能影響降至最低。列遮罩更解決了「既要限制敏感欄,又要保留資料列完整性」的長期難題。