首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle VPD 細粒度存取控制進階實戰:策略類型選型與效能優化

     編輯:Oracle 資料庫基礎

從基礎到進階:為什麼需要多種策略類型?

VPD 核心是 **Policy Function 動態產生 WHERE 條件**。Oracle 9i 僅支援 **Dynamic Policy**:每次查詢、每行資料都呼叫函數 → 高併發下 CPU 飆升。10g 引入四種進階類型,針對「謂詞靜態程度」優化。

謂詞結構分析:靜態部 vs 動態部

WHERE am_name = 'SCOTT'
       ↑         ↑
    靜態部    動態部(隨用戶/上下文變化)

策略類型本質上是在**快取靜態部、僅在動態部真正改變時重新評估**。

四大進階策略類型深度對比

類型快取層級重新評估觸發條件適用場景風險
CONTEXT_SENSITIVESession 級應用上下文 (SYS_CONTEXT) 發生變化謂詞結構固定,值來自上下文(如 balance < SYS_CONTEXT('ctx','maxbal'))低
STATICSGA 級 (跨 Session)**永不**(首次解析後永久快取)謂詞完全由 DB User 決定,會話間不變(多租戶共用 APPUSER,登入觸發器設定 CUST_NAME)高:若上下文實際變了,會回傳錯誤資料
SHARED_CONTEXT_SENSITIVESGA 級 (跨物件)上下文變化 **或** 切換不同物件但上下文未變多表共用同一 Policy Function,上下文相同(如 SAVINGS/CHECKING 同規則)低
SHARED_STATICSGA 級 (跨物件+Session)永不多表共用函數,謂詞完全由 DB User 決定同 STATIC

實戰範例:從 Dynamic 遷移到 Context_Sensitive

1. 建立應用上下文

CREATE OR REPLACE CONTEXT vpdctx USING pkg_vpd_context;

2. 封裝設定上下文的 Package

CREATE OR REPLACE PACKAGE pkg_vpd_context AS
  PROCEDURE set_maxbal(p_val NUMBER);
  PROCEDURE set_cust_name(p_val VARCHAR2);
END;
/
CREATE OR REPLACE PACKAGE BODY pkg_vpd_context AS
  PROCEDURE set_maxbal(p_val NUMBER) IS
  BEGIN DBMS_SESSION.SET_CONTEXT('vpdctx', 'maxbal', p_val); END;
  PROCEDURE set_cust_name(p_val VARCHAR2) IS
  BEGIN DBMS_SESSION.SET_CONTEXT('vpdctx', 'cust_name', p_val); END;
END;
/

3. Policy Function 只組裝謂詞,不查業務表

CREATE OR REPLACE FUNCTION vpd_balance_policy(
  p_schema VARCHAR2, p_table VARCHAR2
) RETURN VARCHAR2 IS
BEGIN
  RETURN 'balance < SYS_CONTEXT(''vpdctx'', ''maxbal'')';
END;
/

4. 掛載策略:指定 CONTEXT_SENSITIVE

BEGIN
  DBMS_RLS.ADD_POLICY(
    object_schema     => 'FINANCE',
    object_name       => 'ACCOUNTS',
    policy_name       => 'BALANCE_LIMIT',
    function_schema   => 'SECURITY',
    policy_function   => 'VPD_BALANCE_POLICY',
    policy_type       => DBMS_RLS.CONTEXT_SENSITIVE,  -- 關鍵
    statement_types   => 'SELECT, INSERT, UPDATE, DELETE',
    sec_relevant_cols => 'BALANCE'
  );
END;
/

5. 應用層登入後設定上下文

-- Java/.NET 連接池取得連接後立即呼叫
BEGIN pkg_vpd_context.set_maxbal(100000); END;
-- 或資料庫登入觸發器
CREATE OR REPLACE TRIGGER set_vpd_ctx_after_logon
AFTER LOGON ON DATABASE
BEGIN
  IF USER = 'APPUSER' THEN
    pkg_vpd_context.set_maxbal(get_user_limit(USER));
  END IF;
END;

Static Policy 陷阱實測

場景:Web 用戶 TAO、KARTHIK 共用 APPUSER,登入觸發器設定 CUST_NAME。
若改用 STATIC,首次登入 TAO 解析 → 謂詞 CUST_NAME='ACME' 寫入 SGA 快取。
隨後 KARTHIK 登入(同 APPUSER),**不重新評估**,直接復用 CUST_NAME='ACME' → **資料洩露**。

鐵律:除非 100% 確定「同一 DB User 的所有 Session、謂詞永遠相同」,**禁用 STATIC**。

Shared 策略:跨表復用謂詞快取

場景:SAVINGS、CHECKING 兩表共用 vpd_balance_policy。
用戶查詢 SAVINGS → 評估函數 → 快取謂詞。
緊接查詢 CHECKING → **Dynamic/Context_Sensitive 會再次評估**(因物件不同)。
改用 SHARED_CONTEXT_SENSITIVE → 偵測到上下文未變、**跨物件復用謂詞**,省一次函數呼叫。

效能量測建議

-- 監控策略命中率
SELECT policy_name, pf_owner, function, policy_type,
       execution_count, total_time/1000 total_ms
FROM DBA_POLICIES p
JOIN V$VPD_POLICY v ON v.POLICY_NAME = p.POLICY_NAME
WHERE p.OBJECT_SCHEMA = 'FINANCE';
  • EXECUTION_COUNT 應遠小於查詢次數(Context_Sensitive/Shared 生效證明)。
  • TOTAL_MS 除以執行次數 = 平均函數耗時,目標 < 1ms。

最佳實踐總結

  1. **預設選 CONTEXT_SENSITIVE**:安全、效能平衡,覆蓋 90%+ 場景。
  2. **謂詞組裝下推應用層**:Policy Function 只拼字串,業務邏輯在登入觸發器/連接池初始化設定上下文。
  3. **嚴禁 STATIC 除非鐵律滿足**;審計時檢查是否誤用。
  4. **多表共用函數 → 加 SHARED 前綴**;單表不需。
  5. **SEC_RELEVANT_COLS** 指定敏感欄,配合 SEC_RELEVANT_COLS_OPT => DBMS_RLS.ALL_ROWS 實現「列級掩碼」而非行級過濾。
  6. 定期查 V$VPD_POLICY 監控執行次數與耗時,異常即優化函數或調整策略類型。

結語

VPD 策略類型的選擇,本質是 **「快取粒度」與「安全性」的權衡**。Dynamic 最安全最慢,Static 最快最危險,Context_Sensitive 是黃金分割點。架構師應在**安全模型設計階段**即規劃上下文命名空間、策略分類、共用函數範圍,而非上線後被效能問題倒逼修改。記住:**Policy Function 越簡單,系統越穩健。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved