1. Documentación en Tahiti -> Oracle Database, 11g Release 2 (11.2) -> Masters Book List -> Security Guide -> 7 Using Oracle Virtual Private Database to Control Data Access
2. Los mecanismos de control de acceso de grano fino (Fine-grained Access Control) nos permiten implementar lo que se conoce como VPD (Virtual Private Database). VPD se utiliza para crear políticas de seguridad adicionales a las que ya conocemos (como GRANT) a nivel de fila y/o columna. Por decirlo de forma más directa, VPD añade una clausula WHERE dinámicamente a las consultas que lanza un usuario contra una tabla, vista o sinónima para filtrar el conjunto de datos que nosotros establezcamos.
3. La mejor forma de entender esta funcionalidad es con un ejemplo. En este objetivo vamos a hacer uno muy sencillo, pero en el siguiente (Create and manage contexts) utilizaremos los contextos para añadir mayor precisión al control de acceso.
Supongamos que queremos limitar el acceso a la tabla ORDERS del esquema OE. Sólo queremos permitir que los usuarios consulten los pedidos del vendedor con código 159. Con los mecanismos de control habituales (GRANT SELECT, …) no es suficiente y es aquí donde utilizamos VPD para conseguirlo.
-- Necesitamos una función que nos devuelva el predicado de nuestro requisito CREATE OR REPLACE FUNCTION auth_orders( schema_var IN VARCHAR2, table_var IN VARCHAR2 ) RETURN VARCHAR2 IS return_val VARCHAR2 (400); BEGIN return_val := 'SALES_REP_ID = 159'; RETURN return_val; END auth_orders; / -- Probamos la función AUTH_ORDERS -- No importa los argumentos de entrada ya que no los usamos en la función SELECT AUTH_ORDERS('BLAH','BLAH') FROM DUAL; -- Ahora creamos la política utilizando el paquete DBMS_RLS -- DBMS_RLS proporciona el interfaz administrtivo de control de acceso de grano fino BEGIN DBMS_RLS.ADD_POLICY ( object_schema => 'oe', object_name => 'orders', policy_name => 'orders_policy', function_schema => 'sys', policy_function => 'auth_orders', statement_types => 'select, insert, update, delete' ); END; / -- Nos conectamos como OE para probar que ya está activo -- Veremos que sólo nos reporta 7 registros cuando la tabla tiene 105 CONN OE/oe SELECT * FROM ORDERS; -- Sin embargo si nos conectamos como SYS veremos todos los registros -- Los usuarios administrativos tienen acceso a todos los registros de la tabla CONN / AS SYSDBA SELECT COUNT(*) FROM OE.ORDERS;
4. También se pueden filtrar datos a nivel de columna. Supongamos que no queremos que la gente vea los salarios de los ejecutivos de una compañía, pero SÍ queremos que vean el resto de los datos, incluidos los ejecutivos.
-- Definimos la función que discrimina los trabajadores ejecutivos (DEPARMENT = 90) -- Fijaros que el predicado dice que sean distintos para filtra CREATE OR REPLACE FUNCTION hide_sal ( v_schema IN VARCHAR2, v_objname IN VARCHAR2) RETURN VARCHAR2 AS con VARCHAR2 (200); BEGIN con := 'DEPARTMENT_ID != 90'; RETURN con; END hide_sal; / -- Definimos la política BEGIN DBMS_RLS.ADD_POLICY ( object_schema => 'hr', object_name => 'employees', policy_name => 'employees_policy', function_schema => 'sys', policy_function => 'hide_sal', statement_types => 'select', sec_relevant_cols => 'salary', sec_relevant_cols_opt => dbms_rls.all_rows ); END; / -- Nos conectamos con el usuario HR para comprobar la política -- Comprobamos que los ejecutivos (DEPARTMENT_ID=90) tienen el campo SALARY=NULL conn hr/hr SELECT FIRST_NAME, LAST_NAME, DEPARTMENT_ID, SALARY FROM EMPLOYEES ORDER BY 3; -- De hecho podríamos consultar los trabajadores que tienen SALARY=NULL SELECT * FROM EMPLOYEES WHERE SALARY IS NULL;
5. En el ejemplo anterior filtrabamos los resultados que pueden ver los usuarios de Oracle. Esto se puede complementar con una auditoría para registrar aquellas personas que vean datos delicados. Continuando con el ejemplo anterior, podemos establecer una política para que registrar todos los accesos que se produzcan sobre los salarios de la compañía.
-- Para ello utilizamos el procedimiento ADD_POLICY del paquete DBMS_FGA -- · Registramos cualquier operación de consulta (SELECT) o DML -- · En AUDIT_TRAIL especificamos que se almacen la consulta y las Bind Variables (DB + EXTENDE) BEGIN DBMS_FGA.ADD_POLICY( object_schema => 'HR', object_name => 'EMPLOYEES', policy_name => 'AUDIT_SALARY', enable => TRUE, statement_types => 'INSERT, UPDATE, SELECT, DELETE', audit_column => 'SALARY', audit_trail => DBMS_FGA.DB + DBMS_FGA.EXTENDED); END; / -- Realizamos una consulta desde el esquema HR SELECT SUM(SALARY) FROM HR.EMPLOYEES; -- Mostramos el contenido de la auditoria SELECT * FROM DBA_FGA_AUDIT_TRAIL;
6. Limpiamos el entorno para continuar con otros objetivos.
-- Borramos las políticas y la función que hemos creado DROP FUNCTION auth_orders; DROP FUNCTION hide_sal; EXEC DBMS_RLS.DROP_POLICY('OE','ORDERS','ORDERS_POLICY'); EXEC DBMS_RLS.DROP_POLICY('HR','EMPLOYEES','EMPLOYEES_POLICY'); EXEC DBMS_FGA.DROP_POLICY('HR','EMPLOYEES','AUDIT_SALARY');