O Oracle Virtual Private Database é uma feature inclusa na versão Enterprise Edition, sendo introduzida a partir do Oracle 8i.
O principal objetivo do VPD é permitir a criação de políticas para acesso aos dados, em nível de linha e coluna (disponibilizada a partir da versão 10g). Basicamente o VPD inclui dinamicamente uma clausula where nas consultas que são realizadas nas tabelas/views/sinônimos que possuem o VPD ativo.
As políticas criadas com o VPD podem ser simples ou complexas, dependendo dos requerimentos de segurança necessários. Estas políticas, por serem associadas diretamente aos objetos no banco de dados, são aplicadas automaticamente a qualquer usuário e meio de acesso aos dados. Desde que estes usuários não tenham a permissão EXEMPT ACCESS POLICY.
Quando um usuário, seja direta ou indiretamente acessa um objeto com VPD ativo, o Oracle modifica a consulta SQL executada. Esta modificação cria uma clausula where retornada por uma função usada na implementação da politica de segurança. A modificação ocorre de forma transparente para o usuário e desta forma não necessita de nenhum ajuste a "nível de aplicação". O VPD pode ser aplicado a operações de select, insert, update, index e delete.
Neste artigo irei abordar um exemplo de criação de VPD "simples" a nível de linha.
Primeiramente estarei realizando a criação de uma tabela chamada notas, na qual estaremos aplicando uma política VPD para que apenas os usuários autorizados possam visualizar as informações contidas.
SQL> show user; USER is "LAMIM" SQL> create table notas( id_aluno number(4), id_curso number (2), nome_aluno varchar2 (100), nota number(4,1) ); 2 3 4 5 6 Table created. SQL>Criada a tabela, vamos inserir alguns valores na mesma afim de possibilitar nossa demonstração de um política VPD.
SQL> SQL> insert into notas values (1,15,'Scot',8.0); 1 row created. SQL> insert into notas values (2,15,'Smith',6.5); 1 row created. SQL> insert into notas values (3,25,'Tiger',3.3); 1 row created. SQL> insert into notas values (4,25,'Sarah',4.7); 1 row created. SQL> insert into notas values (5,25,'Jessie',10); 1 row created. SQL> insert into notas values (7,30,'Roth',9.3); 1 row created. SQL> insert into notas values (8,30,'John',10); 1 row created. SQL> insert into notas values (9,10,'Allen',7.7); 1 row created. SQL> insert into notas values (10,10,'Paul',5.1); 1 row created. SQL> commit; Commit complete.Para que seja possível demonstrar o funcionamento do VPD, será criado o usuário consulta, que terá permissão de leitura na tabela notas.
SQL> create user consulta identified by consulta; User created. SQL> SQL> grant create session to consulta; Grant succeeded. SQL> grant select on notas to consulta; Grant succeeded. SQL> SQL> select * from lamim.notas; ID_ALUNO ID_CURSO NOME_ALUNO NOTA ---------- ---------- ---------- ---------- 1 15 Scot 8 2 15 Smith 6,5 3 25 Tiger 3,3 4 25 Sarah 4,7 5 25 Jessie 10 7 30 Roth 9,3 8 30 John 10 9 10 Allen 7,7 10 10 Paul 5,1 9 rows selected. SQL>Apos a criação do usuário, realizando um select na tabela notas do schema lamim, podemos ver todos os dados da tabela. Porém imagine que exista uma regra de negócio na qual o usuário consulta só pode visualizar os alunos vinculados ao curso de id 15 e 25.
Vamos criar um VPD para atender esta regra. É importante destacar que a complexidade da politica, depende exclusivamente da necessidade de segurança a ser implementada.
Para um controle mais "dinâmico" do meu VPD, estarei criando duas tabelas de controle chamadas DENY_ACESS onde serão cadastrados os usuário que serão afetados (limitados - usuário consulta) pela política e a BLOCKED_ACCESS onde serão cadastrados os registros que serão afetados (limitados id_curso 10 e 30).
SQL> SQL> create table DENY_ACCESS( nome varchar2(50)); 2 Table created. SQL> SQL> insert into DENY_ACCESS values ('CONSULTA'); 1 row created. SQL> create table blocked_access( ID_CURSO number(20) ); 2 3 Table created. SQL> insert into blocked_access values (10); 1 row created. SQL> insert into blocked_access values (30); 1 row created. SQL> commit; Commit complete. SQL> grant select on deny_access to consulta; Grant succeeded. SQL> grant select on blocked_access to consulta; Grant succeeded. SQL>Realizada a criação das tabelas, estaremos criando agora a função que será associada a politica para restrição de acesso. Esta função irá basicamente comparar se o usuário da sessão conectada está cadastrado na blocked_access. Caso o usuário esteja cadastrado, ele cairá na condição que restringe o acesso ao ID_CURSO diferente dos ID_CURSO cadastrados na tabela DENY_ACCESS.
SQL> CREATE OR REPLACE FUNCTION VPD_DENY_ACCESS_NOTAS (schema in varchar2, table_p in varchar2) return varchar2 as 2 3 w_exists number :=0; 4 predicate varchar2(100) default null; 5 BEGIN 6 select max(vlr) into w_exists 7 from (select 0 vlr 8 from dual 9 union 10 select 1 vlr 11 from lamim.deny_access 12 where nome = UPPER(SYS_CONTEXT('USERENV', 'SESSION_USER'))); IF w_exists = 1 13 14 THEN 15 predicate := 'ID_CURSO not in (select ID_CURSO from lamim.blocked_access)'; 16 ELSE 17 predicate := '1=1'; 18 END IF; 19 RETURN predicate; END; 20 21 / Function created. SQL>Após a criação da função, devemos realizar a criação da politica. A documentação da politica pode ser verificada aqui.
SQL> BEGIN DBMS_RLS.ADD_POLICY ( 2 3 object_schema => 'LAMIM', 4 object_name => 'NOTAS', 5 policy_name => 'VPD_DENY_ACCESS_NOTAS', 6 function_schema => 'LAMIM', 7 policy_function => 'VPD_DENY_ACCESS_NOTAS', 8 statement_types => 'SELECT, INSERT, UPDATE,DELETE'); 9 END; 10 / PL/SQL procedure successfully completed. SQL>Assim que a política é criada, nosso VPD já está ativo. Para demonstrar o funcionamento, estarei criando o usuário teste, que não será incluido no bloqueio. Desta forma, em nosso teste, o usuário consulta deverá visualizar todos os dados da tabela consulta, desde que o ID_CURSO seja diferente de 10 e 30 e o usuário teste, conseguirá ver normalmente.
SQL> create user teste identified by teste; User created. SQL> grant create session to teste; Grant succeeded. SQL> grant select on lamim.notas to teste; Grant succeeded. SQL> conn teste/teste Connected. SQL> show user; USER is "TESTE" SQL> set lines 150 SQL> col NOME_ALUNO for a10 SQL> select * from lamim.notas; ID_ALUNO ID_CURSO NOME_ALUNO NOTA ---------- ---------- ---------- ---------- 1 15 Scot 8 2 15 Smith 6,5 3 25 Tiger 3,3 4 25 Sarah 4,7 5 25 Jessie 10 7 30 Roth 9,3 8 30 John 10 9 10 Allen 7,7 10 10 Paul 5,1 9 rows selected. --COM O USUÁRIO TESTE, TEMOS ACESSO A TODOS OS REGISTROS --VAMOS CONECTAR COM O USUARIO RESTRITO NO VPD - USUARIO CONSULTA SQL> conn consulta/consulta Connected. SQL> show user; USER is "CONSULTA" SQL> set lines 150 SQL> col NOME_ALUNO for a10 SQL> select * from lamim.notas; ID_ALUNO ID_CURSO NOME_ALUNO NOTA ---------- ---------- ---------- ---------- 2 15 Smith 6,5 1 15 Scot 8 5 25 Jessie 10 4 25 Sarah 4,7 3 25 Tiger 3,3 SQL> -- COM O USUARIO CONSULTA, SAO LITADOS APENAS OS CURSOS DE ID_CURSO 15 E 25. --MOSTRANDO QUE NOSSA POLITICA FUNCIONOU CONFORME PLANEJADO. SQL>Em um próximo post, estarei abordando a criação de uma política a nível de coluna.
Fonte:
http://www.dba-oracle.com/t_dbms_rls.htm
https://uhesse.com/2013/06/18/fine-grained-access-control-with-dbms_rls-using-update_checktrue/
https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_rls.htm
https://docs.oracle.com/cd/B28359_01/network.111/b28531/vpd.htm
Comentários
Postar um comentário