Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

ABAC no Node.js: Guia Prático

Atualizado em: 27 de agosto de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

O ABAC no Node.js decide acesso com base em atributos do usuário, recurso, ação e ambiente. Em vez de depender apenas de uma função como editor ou administrador, a política pode considerar departamento, proprietário, classificação do dado, horário, região, estado do pedido e nível de autenticação.

ABAC oferece decisões mais precisas que RBAC, mas também aumenta complexidade. Políticas precisam ser legíveis, testáveis, auditáveis e avaliadas com dados confiáveis. Uma regra ambígua ou atributo vindo do cliente pode conceder acesso indevido.

Neste guia, você aprenderá a modelar atributos, criar políticas, implementar um motor simples, combinar RBAC e ABAC, cachear decisões, explicar negações, testar regras e evitar escalada de privilégios.

O que é ABAC?

ABAC significa Attribute-Based Access Control. A publicação NIST SP 800-162 sobre ABAC descreve o modelo. A OWASP Authorization Cheat Sheet reúne recomendações de autorização.

Para um modelo baseado em funções, consulte RBAC no Node.js. Para isolamento entre organizações, veja Multi-Tenancy no Node.js.

Quatro grupos de atributos

  • Sujeito: usuário, serviço, função, departamento, plano.
  • Recurso: proprietário, tenant, classificação, status.
  • Ação: ler, editar, excluir, aprovar, exportar.
  • Ambiente: horário, localização, dispositivo, risco, MFA.

Exemplo de política

Um usuário pode editar um documento quando:

  • pertence ao mesmo tenant;
  • é proprietário ou gerente do departamento;
  • o documento não está bloqueado;
  • a autenticação possui MFA para dados confidenciais.

Contexto de decisão

const context = {
  subject: {
    id: user.id,
    tenantId: identity.tenantId,
    departmentId: membership.departmentId,
    roles: membership.roles,
    mfaLevel: identity.mfaLevel
  },
  resource: {
    type: 'document',
    id: document.id,
    tenantId: document.tenantId,
    ownerId: document.ownerId,
    departmentId: document.departmentId,
    classification: document.classification,
    status: document.status
  },
  action: 'document.update',
  environment: {
    requestTime: new Date(),
    ipRisk: risk.ipLevel
  }
};

Atributos confiáveis

Tenant, usuário e MFA devem vir da autenticação validada. Propriedades do recurso devem vir do banco. Não aceite esses atributos diretamente do corpo.

Política como função

function canUpdateDocument(context) {
  const { subject, resource } = context;

  if (subject.tenantId !== resource.tenantId) {
    return false;
  }

  if (resource.status === 'locked') {
    return false;
  }

  const owner = subject.id === resource.ownerId;
  const manager = subject.roles.includes('department_manager')
    && subject.departmentId === resource.departmentId;

  if (!owner && !manager) {
    return false;
  }

  if (
    resource.classification === 'confidential'
    && subject.mfaLevel !== 'strong'
  ) {
    return false;
  }

  return true;
}

Retorno explicável

function deny(reason, policy) {
  return {
    allowed: false,
    reason,
    policy
  };
}

Explicações ajudam logs e suporte, mas o cliente não deve receber detalhes que revelem atributos sensíveis.

Default deny

Se nenhuma política permite explicitamente, negue. Uma exceção ou atributo ausente não deve liberar o acesso.

Combinação de políticas

Estratégias comuns:

  • deny overrides;
  • permit overrides;
  • first applicable;
  • all must permit.

Para segurança, deny overrides costuma ser mais previsível.

Motor de políticas simples

class PolicyEngine {
  constructor(policies) {
    this.policies = policies;
  }

  evaluate(context) {
    const applicable = this.policies.filter(policy =>
      policy.action === context.action
      && policy.resourceType === context.resource.type
    );

    if (applicable.length === 0) {
      return deny('no_applicable_policy', 'default');
    }

    for (const policy of applicable) {
      const result = policy.evaluate(context);
      if (!result.allowed) return result;
    }

    return { allowed: true };
  }
}

Políticas em código

São fáceis de versionar e testar, mas um deploy é necessário para alterar regras.

Políticas como dados

JSON ou uma linguagem de políticas permite atualização dinâmica, porém exige schema, validação, versionamento, assinatura e sandbox.

Não use eval

Nunca execute expressões arbitrárias de uma política com eval() ou new Function(). Use um interpretador limitado e auditado.

Open Policy Agent

OPA e Rego podem centralizar políticas. A aplicação envia atributos e recebe a decisão. Avalie latência, cache, disponibilidade e governança.

Policy Decision Point

O componente que decide é chamado PDP. O middleware ou serviço que aplica a decisão é o Policy Enforcement Point.

Decisão local

Avaliar no processo reduz latência, mas exige distribuir políticas para todas as instâncias.

Decisão remota

Um serviço central simplifica governança, mas pode virar dependência crítica. Use timeout e fallback seguro.

Falha do PDP

Para operações sensíveis, falhe fechado. Para recursos públicos, uma política local mínima pode ser usada, desde que explicitamente definida.

ABAC e RBAC

Os modelos se complementam. RBAC concede uma capacidade geral, e ABAC restringe pelo contexto:

hasPermission('document.update')
&& document.tenantId === identity.tenantId
&& (
  document.ownerId === identity.userId
  || identity.departmentId === document.departmentId
)

Role explosion

ABAC evita criar roles como editor_do_departamento_financeiro_com_mfa. A role permanece editor e atributos refinam a decisão.

Multi-tenancy

O tenant deve ser a primeira condição de quase toda política. Uma negação cruzada precisa ocorrer antes de outras regras.

Row-Level Security

RLS protege linhas no banco, enquanto ABAC toma decisões de aplicação. Consulte Row-Level Security no Node.js.

Consultando o recurso

Não autorize apenas com o ID da URL. Carregue atributos mínimos do recurso usando tenant e ID.

TOCTOU

Entre verificar e alterar, o recurso pode mudar. Para condições críticas, valide novamente na mesma transação ou use update condicional.

Update condicional

UPDATE documents
SET content = $1,
    version = version + 1
WHERE tenant_id = $2
  AND id = $3
  AND owner_id = $4
  AND status != 'locked'
RETURNING id;

Parte da política pode ser aplicada atomicamente no SQL.

Lock otimista

Inclua versão para impedir que a decisão seja baseada em estado antigo. Consulte Lock Otimista no Node.js.

Atributos ambientais

Horário, IP e dispositivo podem mudar. Use-os apenas quando realmente necessários e trate proxies confiáveis.

Geolocalização

IP não é prova precisa de localização. Não use sozinho para uma decisão de alto risco.

Nível de autenticação

Operações sensíveis podem exigir step-up authentication, como passkey ou TOTP recente.

Tempo desde MFA

const mfaRecent = Date.now() - identity.mfaAt.getTime()
  < 10 * 60 * 1000;

Use horário do servidor e sessão protegida.

Delegação

Um usuário pode delegar acesso temporário. Modele início, fim, escopo, revogação e auditoria.

Regras temporais

Uma permissão com expiração precisa ser verificada a cada decisão ou refletida em tokens curtos.

Cache de decisões

Uma chave pode incluir:

policy:${policyVersion}:${tenantId}:${subjectId}:${resourceId}:${resourceVersion}:${action}

Sem versão de política e recurso, o cache pode conceder acesso antigo.

TTL curto

Decisões sensíveis devem ter TTL pequeno ou não ser cacheadas.

Invalidando cache

Altere uma versão de autorização quando membership, role, classificação ou política mudar.

Dados pessoais

Evite enviar atributos desnecessários a um PDP remoto. Minimize dados e proteja logs.

Logs de decisão

{
  "decision": "deny",
  "action": "document.update",
  "resourceType": "document",
  "policy": "confidential_requires_mfa",
  "tenantId": "...",
  "requestId": "..."
}

Não registre conteúdo do documento, token ou segredo.

Auditoria

Alterações de política precisam registrar autor, versão anterior, versão nova, motivo e aprovação.

Métricas

Monitore decisões negadas, falhas do PDP, latência, políticas sem correspondência e aumento de step-up.

Cardinalidade

Use action, resource type e policy como labels controladas. Não use IDs individuais.

Testes em tabela

const cases = [
  {
    name: 'proprietário edita documento comum',
    context: ownerContext,
    expected: true
  },
  {
    name: 'outro tenant é negado',
    context: crossTenantContext,
    expected: false
  },
  {
    name: 'confidencial sem MFA é negado',
    context: weakMfaContext,
    expected: false
  }
];

Testes de propriedade

Gere atributos aleatórios e verifique invariantes, como “tenants diferentes nunca recebem permit”.

Teste de atributo ausente

Remova cada atributo obrigatório e confirme default deny, sem exceção que libere o acesso.

Teste de cache

Mude a versão do recurso ou política e confirme que a decisão anterior não é reutilizada.

Teste de concorrência

Altere o status do recurso entre leitura e escrita e confirme validação transacional.

Teste de falha do PDP

Simule timeout e verifique o fallback definido.

Revisão de políticas

Procure regras redundantes, atributos não usados, permissões amplas e exceções permanentes.

Erros comuns

  • Atributo vindo do cliente: usuário muda a decisão.
  • Permit por padrão: ausência de política libera acesso.
  • Política sem versão: cache e auditoria ficam inconsistentes.
  • eval em regras: código arbitrário é executado.
  • Contexto enorme: dados sensíveis vazam.
  • Decisão fora da transação: estado muda antes da escrita.
  • Regras impossíveis de explicar: suporte e auditoria falham.

Boas práticas

  • Use atributos confiáveis.
  • Aplique default deny.
  • Comece verificando tenant.
  • Combine RBAC e ABAC.
  • Versione políticas.
  • Evite execução arbitrária.
  • Defina timeout do PDP.
  • Cacheie com versões.
  • Registre decisões sem dados sensíveis.
  • Teste invariantes e atributos ausentes.

Conclusão

O ABAC no Node.js permite decisões de autorização baseadas no contexto real, combinando atributos do usuário, recurso, ação e ambiente. Ele evita criar uma role para cada exceção e oferece controle mais fino.

A flexibilidade exige disciplina. Atributos precisam ser confiáveis, políticas devem negar por padrão e decisões críticas precisam considerar concorrência. Com versionamento, auditoria, testes e integração com RBAC e RLS, ABAC oferece autorização precisa sem transformar regras de acesso em código invisível e impossível de manter.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita