Trilogia CaraCore CSO — Parte 2 de 3

Sessões Opacas e Segurança Pragmática: Adeus JWT no Browser e a Blindagem do CaraCore CSO

Sessões Opacas e Segurança Pragmática

A Fortaleza Relacional: A proteção de acessos corporativos por meio de sessões opacas, controle estrito de perfis e trilha de auditoria em banco de dados.

Tempo de leitura: 7 minutos

Nos últimos dez anos, a indústria de desenvolvimento de software foi engolida por um dogma quase inquestionável: "qualquer aplicação moderna deve utilizar JSON Web Tokens (JWT) armazenados no LocalStorage do navegador". O argumento parecia tentador: autenticação sem estado (stateless), sem tocar no banco de dados e supostamente mais escalável.

Entretanto, na linha de frente dos sistemas corporativos e da gestão operacional de frotas, a teoria do manual acadêmico costuma ruir diante do primeiro incidente de segurança. Se um colaborador é desligado da empresa em um sábado à tarde, como você revoga instantaneamente o acesso dele se o token JWT dele é válido pelas próximas 24 horas? A resposta usual do mercado é criar listas de bloqueio (blacklists) no Redis — transformando a arquitetura "stateless" em um sistema com estado, só que três vezes mais complexo e frágil.

Ao desenhar a segurança do CaraCore CSO, decidimos dar um passo atrás, abandonar modismos e adotar o modelo de Sessões Opacas com Estado no Banco Relacional.

1. Por que Tokens no Browser São um Risco Silencioso

Guardar credenciais ou tokens decodificáveis no cliente (como `localStorage` ou `sessionStorage`) expõe a aplicação a ataques clássicos de XSS (Cross-Site Scripting). Qualquer script malicioso injetado por uma dependência de terceiros tem acesso irrestrito ao token.

No CaraCore CSO, a estratégia de autenticação web adota premissas não negociáveis:

  • Cookies HttpOnly, Secure e SameSite=Lax: O JavaScript do navegador sequer enxerga o identificador de sessão. Ele trafega exclusivamente no cabeçalho HTTP gerenciado pelo próprio browser.
  • Identificadores Opacos (Tokens Aleatórios de Alta Entropia): O cookie `cso_sid` não contém perfil, nem ID de usuário, nem tenant ID codificados em Base64. Ele é apenas uma chave criptográfica aleatória.
  • Estado no PostgreSQL (`tb_web_session`): A validação de quem é o usuário, qual o plano da frota e qual o perfil de acesso é resolvida diretamente no banco em uma consulta indexada ultrarrápida. Se o gestor desativa um usuário, a sessão morre no milissegundo seguinte.

2. O Governo de Acesso em Dois Mundos

Uma falha comum em SaaS B2B é misturar a administração da plataforma com o painel do cliente final. No CaraCore CSO, criamos uma separação estrita entre dois mundos:

  1. O Mundo do Tenant (Frota):
    • ENTREGADOR: Acesso estritamente restrito ao registro de campo e checklist.
    • GESTOR: Visão completa de operação, custos, manutenções e relatórios analíticos.
    • ADMIN: Gestão de usuários do tenant, convites de equipe e aceite dos termos LGPD.
  2. O Mundo da Plataforma (Operador CaraCore — `/cso-ops`):

    Uma área completamente isolada, acessível sob o cookie `cso_ops_sid`, protegida por captcha gráfico local, sem qualquer exposição de rotas na interface pública do cliente. É onde gerenciamos ativações de planos Pix, monitoramos tenants inativos e executamos resets assistidos de contingência.

3. Código em Linha de Frente: O Filtro Defensivo de Sessão

Veja como o filtro de autenticação intercepta as requisições no Quarkus, validando a sessão opaca e rejeitando qualquer desvio de perfil antes que a camada de visualização seja acionada:

package br.com.caracore.cso.core.security;

import br.com.caracore.cso.modules.auth.model.WebSession;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.core.Cookie;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import java.net.URI;
import java.time.LocalDateTime;

@Provider
public class WebAuthFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) {
        String path = requestContext.getUriInfo().getPath();
        if (isRotaPublica(path)) {
            return;
        }

        Cookie sessionCookie = requestContext.getCookies().get("cso_sid");
        if (sessionCookie == null || sessionCookie.getValue().isBlank()) {
            redirecionarParaLogin(requestContext);
            return;
        }

        // Validação no PostgreSQL com verificação de expiração e revogação
        WebSession session = WebSession.find("token = ?1 and expiraEm > ?2", 
                sessionCookie.getValue(), LocalDateTime.now())
                .firstResult();

        if (session == null || !session.usuario.ativo) {
            redirecionarParaLogin(requestContext);
            return;
        }

        // Propaga o contexto autenticado de forma imutável
        requestContext.setProperty("cso.user", session.usuario);
        requestContext.setProperty("cso.tenantId", session.usuario.tenant.id);
    }

    private void redirecionarParaLogin(ContainerRequestContext ctx) {
        ctx.abortWith(Response.seeOther(URI.create("/login?expirado=true")).build());
    }

    private boolean isRotaPublica(String path) {
        return path.equals("/") || path.startsWith("/login") || path.startsWith("/cadastro") || path.startsWith("/assets");
    }
}

4. Conformidade e Trilha Auditável LGPD

Segurança não é apenas impedir invasões; é saber exatamente quem realizou cada operação. No CaraCore CSO, todas as ações sensíveis — cadastro de motoristas, exclusão de registros ou alterações de CNH — geram registros imutáveis na tabela de auditoria LGPD.

O gestor da frota tem acesso a uma tela dedicada de auditoria com filtros por período, usuário e ação, podendo imprimir o relatório em PDF para fins de compliance e fiscalização trabalhista.

Conclusão: Simplicidade é o Mais Alto Grau de Sofisticação

Ao substituir a parafernália de tokens JWT no frontend por sessões opacas gerenciadas pelo PostgreSQL, reduzimos o código em mais de 60%, eliminamos vetores críticos de ataque no navegador e ganhamos controle absoluto sobre o ciclo de vida do usuário.

No terceiro e último artigo desta série, abordaremos o aspecto financeiro e de negócio: como sustentamos planos acessíveis (de R$ 5 a R$ 49/mês), a integração com pagamentos Pix sem intermediários predatórios e a visão do futuro com o modelo Local-First (Bunker Digital).

Dicionário de Termos Técnicos

Termos essenciais para a compreensão da arquitetura de segurança abordada:

Cookie HttpOnly
Diretiva de segurança em cabeçalhos HTTP que impede scripts executados no navegador (como JavaScript) de lerem o conteúdo do cookie, neutralizando roubos de sessão via XSS.
CSRF (Cross-Site Request Forgery)
Tipo de ataque onde comandos maliciosos são transmitidos a partir de um usuário em quem a aplicação web confia, mitigado pelo uso de tokens sincronizados e SameSite cookies.
JWT (JSON Web Token)
Padrão aberto que define uma maneira compacta e autossuficiente para transmitir informações seguras entre partes como um objeto JSON codificado digitalmente.
RBAC (Role-Based Access Control)
Mecanismo de controle de acesso que restringe permissões de sistema com base nos papéis ou funções atribuídos a cada usuário na organização (ex.: Admin, Gestor, Entregador).
Sessão Opaca
Modelo de autenticação onde o cliente recebe apenas uma sequência aleatória de caracteres sem significado interno; os dados e privilégios do usuário ficam armazenados com segurança no banco de dados do servidor.
XSS (Cross-Site Scripting)
Vulnerabilidade em aplicações web que permite a invasores injetarem scripts maliciosos no navegador de outros usuários.