Controle de Acesso: Quando Todo Mundo Consegue Ver e Editar Tudo
No começo, todo mundo é admin. Anos depois, ninguém sabe quem ainda tem acesso nem quem alterou o quê. Papéis, permissões e auditoria: o que dá para resolver em uma tarde.
Renan Montanari
Engenheiro de Software Full-Stack
Introdução: O Teste Mental Incômodo
Faça um teste mental rápido.
Liste quem hoje consegue entrar no seu sistema e ver tudo:
- valores, dados de clientes, histórico de vendas;
- relatórios de faturamento;
- informações de parceiros;
- tudo.
Agora conte quantas dessas pessoas ainda trabalham com você.
Em quase todo negócio pequeno, a resposta é incômoda.
E não é descuido. Não é negligência. É o caminho natural das coisas.
Por Que Ninguém Faz Controle de Acesso no Começo
O Cenário de Sempre
Você começa com 3 pessoas: você, seu sócio e um dev. Todos fazem tudo.
Separar permissão parece burocracia de empresa grande. O sistema nasce com um nível de acesso só: acesso total. E funciona bem assim. Todos confiam uns nos outros. Todos sabem exatamente o que o outro está fazendo.
Aí:
- o time cresce para 5 pessoas;
- alguém sai, mas continua com o login e as senhas;
- entra um estagiário que precisa ver só os pedidos;
- você contrata uma agência externa que precisa acessar a integração com o gateway de pagamento, mas não precisa ver mais nada;
- um freelancer entra por 3 meses e depois sai.
E ninguém nunca volta no sistema para "arrumar as permissões". Porque:
- Parece que funciona: tudo continua de pé.
- Ninguém avisa que é urgente: até dar problema.
- É um problema chato: pior que corrigir um bug.
- Você não vê o risco até ele virar realidade.
O Risco Que Todo Mundo Ignora
Não É Má-Fé, É Acidente
O risco comum não é alguém agir de má-fé. Não é espionagem corporativa. É bem mais banal:
gente apagando ou alterando coisa sem querer, porque tinha permissão para isso.
Exemplos que acontecem toda semana em algum lugar:
- Estágio encerrado: o estagiário continua com acesso 6 meses depois.
- Pedido editado por engano: alguém mexe num campo "só para testar".
- Preço alterado sem querer: a pessoa digita na linha errada e salva sem ninguém revisar.
- Cliente excluído da base: um teste feito com dados reais que nunca foi desfeito.
- Faturamento exposto por engano: alguém abriu a tela errada na reunião com o fornecedor.
- Backup perdido: alguém com acesso total apagou "para limpar" e ninguém tinha cópia.
E a pior parte? Ninguém fica sabendo até ser tarde.
A Pergunta Que Ninguém Consegue Responder
Quando algo dá errado e todos têm o mesmo acesso, aparece a pergunta:
"Quem fez isso? E quando?"
E a resposta é: você não sabe.
Porque não existe como reconstruir o que aconteceu.
Não se trata de achar culpado. Não se trata de desconfiar das pessoas.
Trata-se de conseguir ver o que mudou e voltar atrás.
Permissão Bem Feita Cabe em uma Tarde
Permissão bem feita não é desconfiar das pessoas.
É cada um conseguir fazer o próprio trabalho sem conseguir, por acidente, desfazer o trabalho dos outros.
E duas coisas cabem numa tarde:
- Listar quem tem acesso hoje e remover quem não deveria mais ter.
- Perguntar para quem cuida do seu sistema se é possível saber quem alterou o quê, e quando.
Vamos às duas.
1️⃣ Controle de Acesso por Papel (RBAC)
O Problema: Todo Mundo É Admin
// ❌ Amador: estar logado já basta para fazer qualquer coisa
const isUserAllowed = (user: User) => {
return user.exists;
};
export const API = {
viewCustomers: async (user: User) => {
if (!isUserAllowed(user)) throw new Error("Denied");
return db.customers.findAll();
},
editPrice: async (user: User, productId: string, newPrice: number) => {
if (!isUserAllowed(user)) throw new Error("Denied");
return db.products.update(productId, { price: newPrice });
},
deleteCustomer: async (user: User, customerId: string) => {
if (!isUserAllowed(user)) throw new Error("Denied");
return db.customers.delete(customerId);
},
};Problema: um estagiário consegue apagar cliente. Uma agência externa consegue ver o histórico de preços.
A Solução: Papéis e Permissões
// ✅ Profissional: RBAC (Role-Based Access Control)
enum Role {
ADMIN = "admin", // tudo
MANAGER = "manager", // vê dados, edita clientes
SALES = "sales", // cria pedidos, vê clientes
INTERN = "intern", // só visualiza clientes
EXTERNAL_AGENCY = "external_agency", // só a integração com o gateway
}
// Permissões por papel
const permissions: Record<Role, string[]> = {
[Role.ADMIN]: [
"view:customers",
"edit:customers",
"delete:customers",
"view:prices",
"edit:prices",
"view:sales",
"manage:users",
"view:audit_logs",
],
[Role.MANAGER]: [
"view:customers",
"edit:customers", // não pode apagar
"view:prices",
"view:sales",
"view:audit_logs",
],
[Role.SALES]: [
"view:customers",
"create:orders",
"view:orders", // "só os próprios" exige checar o dono do pedido na query
],
[Role.INTERN]: [
"view:customers", // só leitura
],
[Role.EXTERNAL_AGENCY]: [
"webhook:gateway_integration", // nada mais
],
};
// Uma única regra, usada em todo lugar
const can = (user: User, permission: string) =>
permissions[user.role]?.includes(permission) ?? false;
const assertCan = (user: User, permission: string, message: string) => {
if (!can(user, permission)) throw new ForbiddenError(message);
};
// Middleware para as rotas HTTP
const authorize = (permission: string) => {
return (req: Request, res: Response, next: NextFunction) => {
if (!can(req.user, permission)) {
return res.status(403).json({ error: "Acesso negado" });
}
next();
};
};
// E na camada de serviço, para qualquer caminho que chegue até aqui
export const API = {
viewCustomers: async (user: User) => {
assertCan(user, "view:customers", "Você não tem permissão para ver clientes");
return db.customers.findAll();
},
editPrice: async (user: User, productId: string, newPrice: number) => {
assertCan(user, "edit:prices", "Apenas admins podem editar preços");
return db.products.update(productId, { price: newPrice });
},
deleteCustomer: async (user: User, customerId: string) => {
assertCan(user, "delete:customers", "Apenas admins podem apagar clientes");
return db.customers.delete(customerId);
},
};Mapeie Seus Papéis Reais
Antes de escrever código, escreva a lista. Um exemplo:
- ADMIN (você e seu sócio): tudo.
- MANAGER (gerente de operações): vê dados, edita clientes, gera relatórios, vê os logs de auditoria. Não pode apagar, editar preços ou gerenciar usuários.
- SALES (time de vendas): vê clientes, cria pedidos, vê apenas os pedidos que criou. Não pode ver dados financeiros nem editar clientes.
- SUPPORT (suporte ao cliente): vê o cliente e os pedidos dele, adiciona notas. Não pode editar dados sensíveis nem ver histórico de preço.
- EXTERNAL_GATEWAY_PARTNER (parceiro de pagamento): acesso apenas ao webhook da integração.
- CONTRACTOR (freelancer ou agência): acesso limitado a dados específicos, com data para expirar automaticamente.
2️⃣ Auditoria: Saber Quem Fez o Quê
O Problema: Nenhuma Trilha
Alguém editou um preço. Alguém apagou um cliente. Alguém alterou uma data.
Você não sabe quem. Não sabe quando. Não consegue reverter.
A Solução: Logs de Auditoria
O registro precisa do valor antigo e do valor novo. Por isso ele é feito onde a alteração acontece, na mesma transação: se a alteração for salva, o log também é; se falhar, nenhum dos dois fica.
// ✅ Profissional: registre tudo que importa
interface AuditLog {
id: string;
timestamp: Date;
userId: string;
userEmail: string;
action: "create" | "update" | "delete";
resource: "customer" | "order" | "product";
resourceId: string;
changes: {
field: string;
oldValue: unknown;
newValue: unknown;
}[];
ipAddress?: string;
userAgent?: string;
}
const updatePrice = async (user: User, productId: string, newPrice: number) => {
assertCan(user, "edit:prices", "Apenas admins podem editar preços");
return db.transaction(async (tx) => {
const product = await tx.products.findById(productId);
await tx.products.update(productId, { price: newPrice });
await tx.auditLogs.create({
id: generateId(),
timestamp: new Date(),
userId: user.id,
userEmail: user.email,
action: "update",
resource: "product",
resourceId: productId,
changes: [{ field: "price", oldValue: product.price, newValue: newPrice }],
});
});
};
// Na rota: autentica, autoriza e chama o serviço
app.put(
"/products/:id/price",
authenticate,
authorize("edit:prices"),
(req, res) => updatePrice(req.user, req.params.id, req.body.price),
);Consultar os Logs de Auditoria
// "O que aconteceu com esse cliente?"
const getCustomerHistory = async (customerId: string) => {
return db.auditLogs.find({
where: { resource: "customer", resourceId: customerId },
orderBy: { timestamp: "desc" },
});
};
// Resultado:
// [
// {
// timestamp: "2026-10-05 14:32",
// userEmail: "joao@empresa.com",
// action: "update",
// changes: [{ field: "phone", oldValue: "11987654321", newValue: "11987654322" }],
// },
// {
// timestamp: "2026-10-04 10:15",
// userEmail: "maria@empresa.com",
// action: "update",
// changes: [{ field: "status", oldValue: "active", newValue: "inactive" }],
// },
// ]
// "Quem alterou o quê nesse período?"
const whoEditedWhat = async (startDate: Date, endDate: Date) => {
return db.auditLogs.find({
where: { action: "update", timestamp: { gte: startDate, lte: endDate } },
});
};
// "Essa pessoa apagou alguma coisa?"
const checkDeletions = async (userId: string) => {
return db.auditLogs.find({ where: { userId, action: "delete" } });
};A Tabela de Auditoria (PostgreSQL)
CREATE TABLE audit_logs (
id UUID PRIMARY KEY,
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
user_id UUID NOT NULL, -- sem FK: o log precisa sobreviver à remoção do usuário
user_email VARCHAR(255) NOT NULL,
action VARCHAR(20) NOT NULL, -- 'create', 'update', 'delete'
resource VARCHAR(50) NOT NULL, -- 'customer', 'order', 'product'
resource_id UUID NOT NULL,
changes JSONB NOT NULL, -- [{ field, oldValue, newValue }]
ip_address VARCHAR(45),
user_agent TEXT
);
CREATE INDEX idx_audit_user_timestamp ON audit_logs (user_id, timestamp DESC);
CREATE INDEX idx_audit_resource ON audit_logs (resource, resource_id);
CREATE INDEX idx_audit_action ON audit_logs (action);
-- Histórico de um registro
SELECT * FROM audit_logs
WHERE resource = 'customer' AND resource_id = '6f1c2a90-0000-0000-0000-000000000123'
ORDER BY timestamp DESC;
-- Quem mais apagou coisas nos últimos 7 dias
SELECT user_email, COUNT(*) AS deletions
FROM audit_logs
WHERE action = 'delete' AND timestamp > NOW() - INTERVAL '7 days'
GROUP BY user_email
ORDER BY deletions DESC;Checklist: Quando Alguém Entra ou Sai
Quando contrata:
- Definiu qual papel essa pessoa vai ter?
- Criou uma conta própria para ela, sem compartilhar login?
- Registrou quem tem acesso a quê?
- Ativou a verificação em duas etapas (2FA) nessa conta?
- Avisou o time que essa pessoa tem acesso?
Quando a pessoa sai:
- Removeu o acesso no mesmo dia?
- Trocou as senhas compartilhadas?
- Revogou os tokens de API?
- Conferiu se houve alguma alteração suspeita antes da saída?
- Registrou a saída no log de auditoria?
Hoje mesmo:
- Tem a lista de quem tem acesso atualmente?
- Sabe quantas dessas pessoas ainda trabalham com você?
- Removeu os acessos que não fazem mais sentido?
- Tem registro de quem alterou o quê?
- Consegue responder "o que mudou ontem"?
Implementação Prática: Uma Tarde
Hora 1: logs de auditoria
- Criar a tabela no banco
- Registrar as alterações nos fluxos críticos (preço, cliente, pedido)
Hora 2: RBAC
- Definir seus 3 a 5 papéis principais
- Mapear as permissões por papel
- Atualizar o código de autorização
Hora 3: limpeza
- Listar quem tem acesso hoje
- Remover quem não deveria mais ter
- Atribuir os papéis corretos
Hora 4: painel de auditoria
- Criar uma página simples que mostre:
- quem fez o quê;
- quando foi feito;
- o histórico de mudanças por registro.
O Medo Que Ninguém Comenta
Quando você implementa isso, aparece uma pergunta incômoda:
"E se eu descobrir que alguém fez algo errado?"
Essa é a verdadeira razão pela qual muita gente evita auditoria.
Mas o ponto é este: você descobriria de qualquer jeito na hora de investigar um problema. A diferença é que agora você fica sabendo antes e pode corrigir antes de virar crise.
Além disso, na imensa maioria das vezes não é "alguém fez errado". É "ops, fiz sem querer".
Auditoria não é sobre culpa. É sobre saber o que acontece na sua operação.
Próximos Passos
Se alguma destas frases descreve o seu sistema:
- "Não sei quem tem acesso ao meu sistema."
- "Não consigo reverter uma alteração."
- "Alguém apagou algo e não sei quem foi."
- "Todo mundo entra como admin."
- "Alguém saiu e ainda tem acesso."
Então você precisa disso.
Uma tarde implementando controle de acesso e auditoria economiza semanas de investigação.
E, mais importante, poupa você do susto de descobrir que seus dados foram alterados sem deixar rastro.
Precisa de Ajuda Com Controle de Acesso?
Se o seu sistema está crescendo e você quer garantir que os dados sensíveis estão protegidos, não de hackers, mas de acidentes, posso ajudar com:
- Auditoria de acessos: quem tem acesso a quê e onde estão os riscos
- RBAC implementado: papéis e permissões prontos para produção
- Auditoria automática: registro de tudo que importa e um painel para investigar
- Segurança na arquitetura: um design que protege sem burocratizar
Falar comigo