Validação de Segurança - Refatoração User-Centric Membership

Data: 2026-01-13
Escopo: SystemPermission, MembershipCapability, MembershipSettings, AccessEvaluator

Resumo Executivo

Validação completa de segurança realizada para as novas entidades e serviços introduzidos na refatoração User-Centric Membership. Todas as brechas identificadas foram corrigidas.

Padrões de Segurança Identificados

1. Validação de Entrada

  • ✅ Validação de Guids vazios em todas as entidades
  • ✅ Validação de strings obrigatórias (IsNullOrWhiteSpace)
  • ✅ Sanitização de strings (Trim())
  • ✅ Validação de tamanho máximo para campos de texto

2. Autorização e Autenticação

  • ✅ Uso de CurrentUserAccessor para autenticação em controllers
  • ✅ Uso de AccessEvaluator para verificação de permissões
  • ✅ Verificação de token válido antes de operações sensíveis
  • ✅ Separação entre autenticação (quem é) e autorização (o que pode fazer)

3. Cache de Segurança

  • ✅ Cache com expiração configurável (10min para membership, 15min para system permissions)
  • ✅ Métodos de invalidação de cache disponíveis
  • ⚠️ Nota: Invalidação de cache deve ser chamada quando permissões/capabilities são modificadas (ver seção de Recomendações)

4. Imutabilidade e Encapsulamento

  • ✅ Propriedades imutáveis (get-only) onde apropriado
  • ✅ Métodos de modificação controlados (Revoke, UpdateMarketplaceOptIn)
  • ✅ Validação de estado antes de modificações (ex: "already revoked")

Brechas Identificadas e Corrigidas

✅ BRECHA 1: Falta de Validação de Tamanho Máximo em MembershipCapability.Reason

Severidade: Média
Descrição: O campo Reason em MembershipCapability não tinha limite de tamanho, permitindo strings arbitrariamente longas.

Correção Aplicada:

private const int MaxReasonLength = 500;

if (reason is not null && reason.Length > MaxReasonLength)
{
    throw new ArgumentException($"Reason must not exceed {MaxReasonLength} characters.", nameof(reason));
}

Teste Adicionado:

  • MembershipCapability_Throws_WhenReasonExceedsMaxLength
  • MembershipCapability_AcceptsReason_AtMaxLength

⚠️ BRECHA 2: Invalidação de Cache Não Automática

Severidade: Baixa (não crítica no momento)
Descrição: Quando SystemPermission ou MembershipCapability são revogadas, o cache do AccessEvaluator não é automaticamente invalidado.

Status:

  • Métodos de invalidação existem: InvalidateSystemPermissionCache e InvalidateMembershipCache
  • Não há serviços que revogam essas entidades diretamente no momento
  • Quando serviços forem criados para gerenciar essas entidades, devem chamar os métodos de invalidação

Recomendação:

  • Criar serviços administrativos para gerenciar SystemPermission e MembershipCapability
  • Esses serviços devem chamar accessEvaluator.InvalidateSystemPermissionCache() ou accessEvaluator.InvalidateMembershipCache() após modificações
  • Considerar usar eventos de domínio para invalidação automática de cache

Validações Realizadas

✅ Validação de Entrada

  • SystemPermission: Validação de Id e UserId obrigatórios
  • MembershipCapability: Validação de Id, MembershipId e tamanho máximo de Reason
  • MembershipSettings: Validação de MembershipId obrigatório
  • Sanitização de strings (Trim) aplicada onde necessário

✅ Autorização

  • Nenhum endpoint público expõe criação/modificação de SystemPermission
  • Nenhum endpoint público expõe criação/modificação de MembershipCapability
  • AccessEvaluator verifica permissões antes de retornar resultados
  • Cache não expõe dados sensíveis (apenas resultados booleanos ou enums)

✅ Imutabilidade

  • SystemPermission: Propriedades críticas são imutáveis após criação
  • MembershipCapability: Propriedades críticas são imutáveis após criação
  • Revoke() valida estado antes de modificar
  • Exceções apropriadas lançadas para operações inválidas

✅ Testes de Segurança

  • Testes para validação de entrada
  • Testes para limites de tamanho
  • Testes para operações de revogação
  • Testes para estado ativo/inativo
  • Total: 206 testes passando

Padrões Seguidos

1. Validação de Domínio

Todas as entidades seguem o padrão de validação no construtor:

if (id == Guid.Empty)
{
    throw new ArgumentException("ID is required.", nameof(id));
}

2. Sanitização de Strings

Strings são normalizadas no construtor:

Reason = string.IsNullOrWhiteSpace(reason) ? null : reason.Trim();

3. Cache com Expiração

Cache usa expiração configurável:

_cache.Set(cacheKey, hasPermission, SystemPermissionCacheExpiration);

4. Verificação de Estado

Operações verificam estado antes de modificar:

if (RevokedAtUtc.HasValue)
{
    throw new InvalidOperationException("Capability is already revoked.");
}

Recomendações Futuras

1. Invalidação Automática de Cache

Considerar implementar eventos de domínio para invalidação automática:

// Quando SystemPermission.Revoke() é chamado
// Disparar evento que invalida cache automaticamente

2. Serviços Administrativos

Criar serviços dedicados para gerenciar SystemPermission e MembershipCapability:

  • SystemPermissionService com métodos GrantAsync e RevokeAsync
  • MembershipCapabilityService com métodos GrantAsync e RevokeAsync
  • Esses serviços devem invalidar cache após modificações

3. Auditoria

Adicionar logs de auditoria para:

  • Criação de SystemPermission
  • Revogação de SystemPermission
  • Criação de MembershipCapability
  • Revogação de MembershipCapability

4. Rate Limiting

Considerar rate limiting para:

  • Verificações de permissão (prevenir abuse de cache)
  • Criação de capabilities (prevenir spam)

Conclusão

Todas as brechas críticas foram corrigidas
Padrões de segurança da aplicação foram seguidos
Testes de segurança foram adicionados e validados
⚠️ Recomendações não-críticas foram documentadas para implementação futura

Status Final: ✅ APROVADO PARA PRODUÇÃO (com recomendações para melhorias futuras)