Devido à reescrita de consultas pelo sistema de regras do PostgreSQL, outras tabelas/visões além daquelas usadas na consulta original são acessadas. Quando são usadas regras de atualização, isto pode incluir acesso de escrita às tabelas.
As regras de reescrita não têm um dono separado.
O dono da relação (tabela ou visão) é automaticamente o dono das
regras de reescrita definidas para ela.
O sistema de regras do PostgreSQL altera
o comportamento do sistema de controle de acesso padrão.
Com exceção das regras SELECT associadas às
visões do invocador de segurança
(veja CREATE VIEW, todas as relações
utilizadas devido a regras são verificadas em relação aos
privilégios do dono da regra, e não do usuário que a invoca.
Isto significa que, com exceção das visões do invocador de segurança,
os usuários precisam apenas dos privilégios necessários para as
tabelas/visões que são explicitamente indicadas em suas consultas.
Por exemplo: um usuário possui uma lista de telefones onde alguns são privados, outros são de interesse do assistente do escritório. O usuário pode construir assim:
CREATE TABLE phone_data (person text, phone text, private boolean);
CREATE VIEW phone_number AS
SELECT person, CASE WHEN NOT private THEN phone END AS phone
FROM phone_data;
GRANT SELECT ON phone_number TO assistant;
Ninguém, exceto aquele usuário (e os superusuários do banco de dados),
pode acessar a tabela phone_data.
Mas devido ao GRANT, o assistente pode executar
o SELECT na visão phone_number.
O sistema de regras irá reescrever o SELECT em
phone_number em um SELECT em
phone_data.
Como o usuário é o dono de phone_number e,
portanto, o dono da regra, o acesso de leitura a
phone_data agora é verificado em relação aos
privilégios do usuário, e a consulta é permitida.
A verificação de acesso a phone_number também
é realizada, mas isto é feito com relação ao usuário chamador,
portanto, ninguém além do usuário e do assistente pode usar a visão.
Os privilégios são verificados regra por regra.
Portanto, o assistente é, por enquanto, o único que pode ver os
números de telefone públicos.
Mas o assistente pode configurar outra visão e conceder acesso
à mesma ao público.
Então, qualquer um poderá ver os dados de
phone_number através da visão do assistente.
O que o assistente não pode fazer é criar uma visão que acesse
diretamente phone_data.
(Na verdade, o assistente pode, mas não irá funcionar, porque todos
os acessos serão negados durante as verificações de permissão.)
E assim que o usuário perceber que o assistente abriu sua visão
phone_number, o usuário poderá revogar o acesso
do assistente.
Imediatamente, qualquer acesso à visão do assistente falharia.
Pode-se pensar que esta verificação regra por regra é uma falha
de segurança, mas, na verdade, não é.
Mas se não funcionasse assim, o assistente poderia definir uma
tabela com as mesmas colunas de phone_number,
e copiar os dados para lá uma vez por dia.
Então, são os dados do próprio assistente, e o assistente pode
conceder acesso a todos que desejar.
Um comando GRANT significa
“Eu confio em você”.
Se alguém em que se confia fizer algo assim, é hora de pensar
sobre isto e então usar o comando REVOKE.
Note que enquanto as visões podem ser usadas para ocultar o conteúdo
de certas colunas usando a técnica mostrada acima, elas não podem
ser usadas para ocultar de forma confiável os dados em linhas
invisíveis, a menos que tenha sido definido o sinalizador
security_barrier.
Por exemplo, a visão a seguir é insegura:
CREATE VIEW phone_number AS
SELECT person, phone FROM phone_data WHERE phone NOT LIKE '412%';
Esta visão pode parecer segura, já que o sistema de regras irá
reescrever qualquer SELECT de
phone_number em SELECT de
phone_data, e adicionar a qualificação de que
somente se deseja as entradas onde phone não
começa com 412.
Mas se o usuário puder criar suas próprias funções, não será difícil
convencer o planejador a executar a função definida pelo usuário
antes da expressão NOT LIKE.
Por exemplo:
CREATE FUNCTION tricky(text, text) RETURNS bool AS $$
BEGIN
RAISE NOTICE '% => %', $1, $2;
RETURN true;
END;
$$ LANGUAGE plpgsql COST 0.0000000000000000000001;
SELECT * FROM phone_number WHERE tricky(person, phone);
Cada pessoa e número de telefone na tabela
phone_data será mostrada como um
NOTICE, porque o planejador escolherá executar
a função tricky barata antes da função
NOT LIKE mais cara.
Mesmo que o usuário seja impedido de definir novas funções, podem
ser usadas as funções internas em ataques semelhantes.
(Por exemplo, a maioria das funções de conversão inclui seus
valores de entrada nas mensagens de erro que produzem.)
Considerações semelhantes se aplicam às regras de atualização.
Nos exemplos da seção anterior, o dono das tabelas no banco de dados
de exemplo pode conceder os privilégios SELECT,
INSERT, UPDATE, e
DELETE, na visão cadarço para
outra pessoa, mas apenas SELECT na tabela
cadarço_log.
A ação da regra para escrever entradas de registro ainda será
executada com êxito, e este outro usuário poderá ver as entradas
de registro.
Mas não poderia criar entradas falsas, nem manipular ou remover as
existentes.
Neste caso, não há possibilidade de subverter as regras convencendo
o planejador a alterar a ordem das operações, porque a única regra
que referencia cadarço_log é um
INSERT não qualificado.
Isto pode não ser verdade em cenários mais complexos.
Quando for necessário que uma visão forneça segurança no nível de
linha, o atributo security_barrier deverá ser
aplicado à visão.
Isto impede que funções e operadores escolhidos de forma maliciosa
recebam valores de linhas até que a visão tenha feito seu trabalho.
Por exemplo, se a visão mostrada acima tivesse sido criada da
seguinte forma, ela seria segura:
CREATE VIEW phone_number WITH (security_barrier) AS
SELECT person, phone FROM phone_data WHERE phone NOT LIKE '412%';
As visões criadas com a security_barrier podem ter
um desempenho muito pior do que as visões criadas sem esta opção.
Em geral, não há como evitar isto: o plano mais rápido possível
deve ser rejeitado se puder comprometer a segurança.
Por este motivo, esta opção não é ativada por padrão.
O planejador de consultas tem mais flexibilidade ao lidar com
funções que não possuem efeitos colaterais.
Estas funções são referidas como LEAKPROOF,
e incluem muitos operadores simples e comumente usados, como
muitos operadores de igualdade.
O planejador de consulta pode permitir com segurança que estas
funções sejam avaliadas em qualquer ponto do processo de execução
da consulta, porque chamá-las em linhas invisíveis para o usuário
não irá vazar nenhuma informação sobre as linhas não vistas.
Além disso, as funções que não recebem argumentos, ou que não
recebem nenhum argumento da visão de barreira de segurança, não
precisam ser marcadas como LEAKPROOF para serem
empurradas para baixo, porque nunca recebem dados da visão.
Em contraste, uma função que pode relatar um erro dependendo dos
valores recebidos como argumentos (como uma que relata um erro em
caso de estouro ou divisão por zero) não é à prova de vazamentos,
podendo fornecer informações significativas sobre as linhas não
vistas se aplicada antes dos filtros de linha da visão de segurança.
Por exemplo, uma varredura de índice não pode ser selecionada para
consultas em visões de barreira de segurança (ou em tabelas com
políticas de segurança no nível de linha) se um operador usado na
cláusula WHERE estiver associado à família de
operador do índice, mas sua função subjacente não estiver marcada
como LEAKPROOF.
O meta-comando
\dAo+
do psql é útil para listar as famílias de
operador e determinar quais deles estão marcados como sendo
à prova de vazamentos.
É importante entender que até mesmo uma visão criada com a opção
security_barrier é destinada a ser segura apenas
no sentido limitado de que o conteúdo das tuplas invisíveis não
será passado para funções possivelmente inseguras.
O usuário pode ter outros meios de fazer inferências sobre os dados
não vistos; por exemplo, podem ver o plano de consulta usando
EXPLAIN, ou medir o tempo de execução de
consultas em relação à visão.
Um invasor mal-intencionado pode inferir algo sobre a quantidade
de dados não vistos, ou até mesmo obter algumas informações sobre
a distribuição dos dados ou valores mais comuns (já que estas coisas
podem afetar o tempo de execução do plano; ou ainda, visto que
também se refletem nas estatísticas do otimizador, a escolha do plano).
Se estes tipos de ataques de "canal encoberto"
[122]
forem motivo de preocupação, provavelmente não é aconselhável
conceder qualquer acesso aos dados.
[122] covert channel: Um canal intra-sistema não intencional ou não autorizado permitindo que duas entidades cooperantes transfiram informações em uma forma que viole a política de segurança do sistema, mas não exceda as autorizações de acesso das entidades.