Row-level security: controle de acesso granular
1. Introdução à Row-Level Security (RLS)
1.1. O que é RLS e por que ela é necessária
Row-Level Security (RLS) é um mecanismo de segurança de banco de dados que permite controlar o acesso a linhas individuais de uma tabela com base nas características do usuário ou da sessão. Diferentemente dos modelos tradicionais de permissão (que operam no nível de tabela ou coluna), o RLS aplica filtros automáticos e invisíveis ao usuário, garantindo que cada consulta retorne apenas as linhas que o usuário tem autorização para ver.
A necessidade do RLS surge em cenários onde diferentes usuários compartilham a mesma tabela física, mas precisam enxergar subconjuntos distintos de dados. Sem RLS, seria necessário criar views separadas ou implementar lógica de filtragem no código da aplicação, aumentando a complexidade e o risco de falhas de segurança.
1.2. Diferença entre RLS e permissões tradicionais
Permissões tradicionais (GRANT/REVOKE) operam no nível de objeto: um usuário pode ou não acessar uma tabela inteira, ou colunas específicas. Já o RLS opera no nível de linha: mesmo que um usuário tenha permissão total sobre uma tabela, ele só enxergará as linhas que a política de segurança permitir.
| Aspecto | Permissões Tradicionais | RLS |
|---|---|---|
| Escopo | Tabela/Coluna | Linha individual |
| Controle | Binário (tem/não tem acesso) | Granular (filtro dinâmico) |
| Implementação | GRANT/REVOKE | Políticas + Funções predicado |
1.3. Casos de uso típicos
- Multi-tenancy: aplicações SaaS onde cada cliente (tenant) possui dados isolados na mesma tabela
- Compliance (LGPD/GDPR): garantir que usuários vejam apenas dados pessoais aos quais têm direito
- Dados departamentais: funcionários de RH veem apenas registros de seu departamento
- Hierarquia organizacional: gerentes veem dados de sua equipe, diretores veem dados de toda a empresa
2. Conceitos Fundamentais do RLS
2.1. Políticas de segurança
Uma política de segurança é uma regra que define quais linhas são visíveis ou modificáveis para um determinado papel de banco de dados. Cada política está associada a uma tabela específica e pode ser aplicada a operações SELECT, INSERT, UPDATE e DELETE de forma independente.
2.2. Funções de predicado
As funções de predicado são expressões SQL que retornam verdadeiro ou falso para cada linha. Quando uma consulta é executada, o banco de dados adiciona automaticamente o predicado da política à cláusula WHERE, filtrando as linhas que não atendem à condição.
2.3. Contexto de sessão e variáveis de aplicação
O RLS utiliza informações do contexto da sessão para determinar quais linhas devem ser exibidas. As principais variáveis disponíveis são:
current_user: nome do usuário do banco de dadoscurrent_setting('app.tenant_id'): variável de aplicação configurada na sessão- Funções customizadas que retornam o identificador do usuário logado
3. Implementação Prática de RLS no PostgreSQL
3.1. Habilitando RLS em uma tabela
-- Criação da tabela exemplo
CREATE TABLE pedidos (
id SERIAL PRIMARY KEY,
cliente_id INTEGER NOT NULL,
valor DECIMAL(10,2),
status VARCHAR(20)
);
-- Habilita RLS na tabela
ALTER TABLE pedidos ENABLE ROW LEVEL SECURITY;
3.2. Criando políticas com CREATE POLICY
-- Política que permite ao usuário ver apenas seus próprios pedidos
CREATE POLICY pedidos_usuario_policy ON pedidos
FOR SELECT
USING (cliente_id = current_user_id());
-- Política para INSERT com validação (WITH CHECK)
CREATE POLICY pedidos_insert_policy ON pedidos
FOR INSERT
WITH CHECK (cliente_id = current_user_id());
3.3. Políticas para diferentes operações
-- Política para UPDATE: só permite alterar pedidos pendentes do próprio usuário
CREATE POLICY pedidos_update_policy ON pedidos
FOR UPDATE
USING (cliente_id = current_user_id() AND status = 'PENDENTE')
WITH CHECK (cliente_id = current_user_id());
-- Política para DELETE: apenas administradores podem excluir
CREATE POLICY pedidos_delete_policy ON pedidos
FOR DELETE
USING (current_user = 'admin');
4. Gerenciamento de Múltiplos Tenants com RLS
4.1. Estrutura de tabela com coluna tenant_id
CREATE TABLE clientes (
id SERIAL PRIMARY KEY,
tenant_id INTEGER NOT NULL,
nome VARCHAR(100),
email VARCHAR(100)
);
ALTER TABLE clientes ENABLE ROW LEVEL SECURITY;
4.2. Configuração de variáveis de sessão por aplicação
-- Função para obter o tenant_id da sessão
CREATE OR REPLACE FUNCTION get_tenant_id()
RETURNS INTEGER AS $$
BEGIN
RETURN current_setting('app.tenant_id')::INTEGER;
EXCEPTION
WHEN OTHERS THEN RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- Política baseada na variável de sessão
CREATE POLICY clientes_tenant_policy ON clientes
FOR ALL
USING (tenant_id = get_tenant_id());
4.3. Testando isolamento entre tenants
-- Sessão do Tenant 1
SET app.tenant_id = 1;
SELECT * FROM clientes; -- Retorna apenas clientes do tenant 1
-- Sessão do Tenant 2
SET app.tenant_id = 2;
SELECT * FROM clientes; -- Retorna apenas clientes do tenant 2
5. RLS em Ações: Exemplos com Código
5.1. Política simples: filtrar por usuário logado
-- Tabela de tarefas
CREATE TABLE tarefas (
id SERIAL PRIMARY KEY,
usuario_responsavel VARCHAR(50),
descricao TEXT,
concluida BOOLEAN DEFAULT FALSE
);
ALTER TABLE tarefas ENABLE ROW LEVEL SECURITY;
CREATE POLICY tarefas_usuario_policy ON tarefas
FOR SELECT
USING (usuario_responsavel = current_user);
5.2. Política com subconsulta
-- Tabela de permissões auxiliar
CREATE TABLE permissoes_projeto (
usuario VARCHAR(50),
projeto_id INTEGER
);
-- Política que verifica permissão em tabela auxiliar
CREATE POLICY documentos_projeto_policy ON documentos
FOR SELECT
USING (projeto_id IN (
SELECT projeto_id FROM permissoes_projeto
WHERE usuario = current_user
));
5.3. Política para UPDATE garantindo registros próprios
CREATE POLICY tarefas_update_policy ON tarefas
FOR UPDATE
USING (usuario_responsavel = current_user AND NOT concluida)
WITH CHECK (usuario_responsavel = current_user);
6. Desempenho e Boas Práticas
6.1. Impacto na performance
O RLS adiciona overhead a cada consulta, pois o predicado da política é avaliado para todas as linhas. Para minimizar o impacto:
- Crie índices nas colunas usadas nas políticas (ex:
tenant_id,usuario_responsavel) - Use
EXPLAIN ANALYZEpara verificar se os índices estão sendo utilizados - Evite subconsultas complexas nas políticas
6.2. Evitando conflitos com triggers
-- Verifique se triggers não contornam as políticas
-- Exemplo: trigger que insere dados sem respeitar WITH CHECK
CREATE OR REPLACE FUNCTION trigger_insercao_auditoria()
RETURNS TRIGGER AS $$
BEGIN
-- Ação que pode burlar a política
INSERT INTO auditoria VALUES (NEW.*);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
6.3. Monitoramento e depuração
-- Visualizar políticas existentes
SELECT * FROM pg_policies WHERE tablename = 'pedidos';
-- Analisar plano de execução com RLS ativo
EXPLAIN ANALYZE SELECT * FROM pedidos;
7. RLS vs. Alternativas de Controle de Acesso
7.1. Comparação com views filtradas
| Aspecto | RLS | Views Filtradas |
|---|---|---|
| Manutenção | Centralizada no banco | Requer criação de múltiplas views |
| Performance | Otimizador pode usar índices | Pode ter overhead de materialização |
| Flexibilidade | Políticas dinâmicas por operação | Estáticas por definição |
7.2. Comparação com permissões no backend
- RLS: segurança no banco de dados, não pode ser contornada pela aplicação
- Backend: flexível, mas vulnerável a erros de implementação
7.3. Quando NÃO usar RLS
- Cenários de altíssima concorrência onde o overhead é crítico
- Dados não sensíveis onde o controle granular é desnecessário
- Bancos de dados que não suportam RLS nativamente (MySQL, SQL Server até versões recentes)
8. Considerações Finais e Próximos Passos
8.1. Resumo dos benefícios
O RLS oferece uma camada adicional de segurança que opera diretamente no banco de dados, garantindo que mesmo que a aplicação seja comprometida, os dados permaneçam protegidos. É especialmente valioso em arquiteturas multi-tenant e ambientes regulados.
8.2. Integração com outros temas
- Audit logging: combine RLS com triggers de auditoria para rastrear acessos
- Encryption: use RLS para controlar acesso a colunas com dados criptografados
- Backup e restore: políticas RLS são preservadas durante operações de backup
8.3. Próximos passos
Para aprofundamento, explore:
- Políticas hierárquicas (gerente vendo dados da equipe)
- RLS com funções imutáveis para melhor performance
- Testes de segurança automatizados com RLS
Referências
- PostgreSQL Documentation: Row Security Policies — Documentação oficial completa sobre implementação de RLS no PostgreSQL
- Microsoft SQL Server: Row-Level Security — Guia oficial da Microsoft para implementação de RLS no SQL Server
- AWS RDS: Implementing Row-Level Security in PostgreSQL — Artigo técnico da AWS sobre boas práticas de RLS em ambiente cloud
- Percona Blog: Row-Level Security in PostgreSQL - Performance Considerations — Análise detalhada do impacto do RLS na performance de consultas
- Cybertec: Row-Level Security in PostgreSQL - A Practical Guide — Guia prático com exemplos avançados de políticas RLS