傳統 VPD (Virtual Private Database / FGAC) 透過策略函數動態拼接 WHERE 子句,實現**行級**安全。但業務常需:**全體可見某表所有行,但薪資、獎金等敏感欄位僅授權角色可見,其他人看見 NULL**。Oracle 10g 引入 **Column Masking(列值遮罩)** 完美解決此需求。
若無 ALL_ROWS,查詢包含敏感欄位時會直接套用策略函數過濾行;有 ALL_ROWS 時,行全返,敏感欄位轉 NULL。
CREATE OR REPLACE FUNCTION rls_dept (
obj_owner IN VARCHAR2,
obj_name IN VARCHAR2
) RETURN VARCHAR2 AS
predicate VARCHAR2(200);
BEGIN
predicate := 'department_id = 60'; -- 實務中可根據 SYS_CONTEXT 判斷用戶部門
RETURN predicate;
END rls_dept;
/
-- 測試授權
GRANT EXECUTE ON rls_dept TO PUBLIC;
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'HR',
object_name => 'EMPLOYEES',
policy_name => 'restrict_dept_policy',
function_schema => 'HR',
policy_function => 'rls_dept',
sec_relevant_cols => 'salary,commission_pct', -- 敏感欄位清單
sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS -- 關鍵:啟用遮罩模式
);
END;
/
-- 移除策略:DBMS_RLS.DROP_POLICY('HR','EMPLOYEES','restrict_dept_policy');
| 查詢語句 | 執行結果 | 說明 |
|---|---|---|
SELECT * FROM employees; | 返回所有行,salary/commission_pct 顯示 NULL | 未查詢敏感欄位,策略不觸發,但遮罩生效 |
SELECT first_name, salary FROM employees; | 返回所有行,salary 顯示 NULL | 查詢含敏感欄位,遮罩生效 |
SELECT first_name FROM employees WHERE department_id=60; | 僅返回部門 60 的行,salary 正常顯示 | 滿足策略函數條件,視為授權用戶,敏感欄位解除遮罩 |
DBMS_RLS.ADD_POLICY(..., policy_type => DBMS_RLS.CONTEXT_SENSITIVE) 緩存策略謂詞,減少函數呼叫開銷。列值遮罩以「最小權限原則」在資料庫層原生實現欄位級脫敏,零改造應用程式,零效能損耗(除策略函數計算),是合規、多租戶、外包開發場景的首選方案。