Pular para o conteúdo

Segurança

O Floopy fica entre sua aplicação e os provedores de LLM, processando chaves de API, prompts, respostas e dados de faturamento em escala. A segurança é incorporada em cada camada — desde o runtime Rust, que elimina classes inteiras de vulnerabilidades em tempo de compilação, até o sistema de criptografia em camadas que protege seus dados em repouso e em trânsito.

Princípios de Segurança

O modelo de segurança do Floopy é construído em torno de três princípios:

Defesa em profundidade. Cada requisição passa por múltiplas camadas de segurança independentes (rate limiting, autenticação, validação de assinatura, LLM firewall) antes de chegar a um provedor. Uma falha em uma camada não compromete as demais.

Zero trust no conteúdo. Prompts e respostas são tratados como entrada não confiável. O LLM firewall verifica ataques de injeção e conteúdo inseguro antes de encaminhar. Logs contendo conteúdo sensível passam por remoção automática de PII.

Falhar com segurança, não falhar aberto. Falhas em dependências externas (ClickHouse fora do ar, Redis inacessível, timeout do provedor) degradam a funcionalidade de forma controlada, sem expor dados ou burlar verificações de segurança. Falhas de autenticação rejeitam a requisição — nunca a deixam passar.

Separação Arquitetural

graph TB
    subgraph Gateway["Olympus — AI Gateway (Rust)"]
        RL[Rate Limiter] --> Auth[API Key Auth]
        Auth --> Sub[Subscription Check]
        Sub --> FW[LLM Firewall]
        FW --> SSRF[SSRF Validation]
        SSRF --> Router[Provider Router]
    end

    subgraph Dashboard["Zeus — Dashboard (Next.js)"]
        SA[Supabase Auth] --> RBAC[Org Access Control]
        RBAC --> Actions[Server Actions]
    end

    App[Your Application] --> Gateway
    Gateway --> Providers[LLM Providers]
    Gateway -.->|Async Logs| CH[(ClickHouse)]
    Dashboard --> Supabase[(Supabase)]
    Dashboard --> CH

O gateway e o dashboard são arquiteturalmente separados. O Zeus se conecta diretamente ao Supabase e ao ClickHouse — nunca faz proxy pelo Olympus. Um gateway comprometido não consegue acessar dados do dashboard, e um dashboard comprometido não afeta o processamento de requisições do gateway.

Segurança de Chaves de API

Formato da Chave

As chaves de API do Floopy utilizam um formato estruturado com prefixo e checksum:

flo_sk_live_<32_random_chars>_<crc32_checksum>
  • Prefixo flo_sk_ — permite detecção automática por ferramentas de varredura de segredos (GitHub Advanced Security, GitGuardian, TruffleHog). Se sua chave vazar em um repositório público, essas ferramentas a identificam instantaneamente.
  • Modo live / test — distingue chaves de produção de chaves de sandbox.
  • Checksum CRC-32 — permite validação no lado do cliente antes de fazer uma requisição de rede. Detecta erros de digitação e truncamento imediatamente.

Armazenamento de Chaves

As chaves de API nunca são armazenadas em texto puro. Quando você cria uma chave, ela é exibida uma única vez — depois é hasheada com SHA-256 antes do armazenamento. Toda consulta subsequente compara hashes, não valores em texto puro. Não há como recuperar a chave original a partir do banco de dados.

Cache de Autenticação

As consultas de chaves são armazenadas em cache no Redis com um TTL configurável para evitar idas ao banco de dados a cada requisição. Quando você revoga ou rotaciona uma chave no dashboard, o cache é invalidado imediatamente — a revogação entra em vigor em segundos, não em minutos.

Criptografia de Chaves de Provedor

Suas chaves de API de provedores de LLM (OpenAI, Anthropic, Gemini, etc.) são criptografadas em repouso usando criptografia de envelope XChaCha20-Poly1305:

  • Cada chave de provedor recebe sua própria Data Encryption Key (DEK)
  • A DEK é criptografada por uma Key Encryption Key (KEK) gerenciada via KMS
  • Nonces aleatórios de 192 bits eliminam riscos de colisão por paradoxo do aniversário que afetam AES-GCM (nonces de 96 bits)
  • As chaves são descriptografadas apenas em tempo de execução ao encaminhar para o provedor — nunca ficam em cache em texto puro
  • O material da DEK em texto puro é apagado da memória (zeroize) imediatamente após o uso

Rotação de KEK

A KEK usada para envelopar cada DEK pode ser rotacionada sem downtime. Múltiplas versões de KEK coexistem: novas chaves de provedor são criptografadas com a KEK atual, enquanto ciphertexts existentes continuam sendo descriptografados pela KEK que originalmente os envelopou. Cada registro criptografado carrega sua versão de KEK e o timestamp da criptografia para fins de auditoria, e o byte de versão é criptograficamente ligado ao ciphertext via AEAD — qualquer alteração falha na autenticação em vez de forçar a busca de outra chave.

Rate Limiting

O Floopy implementa rate limiting em camadas para prevenir abuso e ao mesmo tempo ser justo com clientes empresariais:

TierKeyDefault LimitPurpose
AnônimoEndereço IP20 rpmBloquear abuso não autenticado
AutenticadoID da OrganizaçãoBaseado em plano (RPS / 10s / RPM)Uso justo (não por IP — seguro atrás de NATs)
Por ChaveID da Chave de APIConfigurávelControle granular por aplicação

Tiers autenticados aplicam três janelas deslizantes simultâneas — 1 segundo (RPS), 10 segundos (burst) e 60 segundos (RPM) — avaliadas atomicamente em um único round-trip no Redis. Quando uma requisição excede uma janela, a resposta retorna 429 com o header Floopy-RateLimit-Exceeded: rps|w10|w60 identificando qual janela foi excedida. Padrões por plano: Free 5/50/60, Starter 20/200/300, Pro 100/1.000/10.000, Enterprise personalizado.

Os rate limits usam janelas deslizantes atômicas no Redis para consistência em escalabilidade horizontal. Requisições autenticadas são limitadas por organização, não por IP — isso evita limitação indevida para clientes empresariais atrás de NATs corporativos ou IPs de saída compartilhados.

LLM Firewall

Camada unica de seguranca de prompt executada antes de qualquer requisicao chegar a um provedor de LLM.

Um LLM ajustado para seguranca (configurado por FIREWALL_MODEL, padrao meta-llama/Llama-Guard-4-12B no Together — a mesma notacao aceita Bedrock ou distribuicoes ponderadas) classifica cada prompt como safe ou unsafe. Categorias consideradas inseguras: injecao de prompt, tentativas de jailbreak, autolesao, conteudo sexual envolvendo menores, instrucoes de atividades ilegais, discurso de odio.

Um cache de vereditos no Qdrant fica na frente da chamada ao LLM. Quando o embedding da requisicao bate com um veredito unsafe recente acima do FIREWALL_SEMANTIC_CACHE_THRESHOLD (padrao 0.95), o veredito em cache evita a chamada ao LLM. Apenas vereditos unsafe sao cacheados — safe sempre e recalculado para que uma troca de modelo possa inverter o resultado sem etapa manual.

  • Ative por requisicao via header floopy-llm-security-enabled: true
  • Bloqueado pelo plano via has_advanced_firewall
  • Requisicoes bloqueadas retornam 400 PROMPT_THREAT_DETECTED
  • Cada chamada registra backend + model_ref na linha do request; cache hits gravam model_ref="cache:firewall_verdicts"
  • Comportamento fail-open: qualquer falha do LLM (rede, parse) deixa a requisicao passar com log loud

Proteção contra SSRF

O gateway valida todas as requisições de saída contra uma lista de permissões estrita de provedores:

  • Apenas hostnames de provedores conhecidos são permitidos (api.openai.com, api.anthropic.com, generativelanguage.googleapis.com, api.groq.com, api.mistral.ai, api.deepseek.com)
  • Resultados de resolução DNS são verificados contra faixas de IP privadas/reservadas (RFC 1918, RFC 6598, link-local, loopback, CGNAT)
  • URLs fornecidas pelo cliente nunca influenciam o destino — o provedor é determinado pelo mapeamento de modelo
  • Tentativas de SSRF são registradas como eventos de segurança

Sanitização de Headers

Os headers do cliente são sanitizados antes de serem encaminhados aos provedores usando uma abordagem de blocklist:

  • Removidos: authorization, cookie, set-cookie, proxy-authorization, x-forwarded-for, x-forwarded-host, x-forwarded-proto, x-real-ip, host
  • Encaminhados: Todos os demais headers, incluindo os específicos de provedores (anthropic-version, OpenAI-Organization)
  • A autenticação do provedor é injetada após a remoção — suas chaves de provedor nunca se misturam com headers do cliente

Remoção de PII

Os corpos de requisição e resposta passam por remoção automática de PII antes do registro no ClickHouse:

PatternExampleReplacement
Endereços de emailuser@example.com[REDACTED:email]
Números de CPF123.456.789-00[REDACTED:cpf]
SSN123-45-6789[REDACTED:ssn]
Números de cartão de crédito4111 1111 1111 1111[REDACTED:credit_card]
Números de telefone+55 11 91234-5678[REDACTED:phone]
Chaves de APIsk-abc123...[REDACTED:api_key]
Tokens BearerBearer eyJ...[REDACTED:bearer]

A remoção acontece no caminho assíncrono de logging — nunca bloqueia ou desacelera sua requisição.

Redação de Atributos de Trace

Além da remoção de PII dos corpos, os atributos de span (metadados anexados aos traces distribuídos) passam por uma camada dedicada de redação antes de serem enviados ao ClickHouse ou a qualquer coletor OTLP por organização. Expressões regulares detectam tokens Bearer ..., chaves de provedor no formato sk-... / sk-ant-... / AIza..., e valores opacos longos típicos de segredos; chaves de atributo sensíveis (authorization, api_key, token, secret, password) são redigidas por completo independentemente do valor. A redação acontece na camada do worker, então é aplicada de forma uniforme no sink ClickHouse e em todos os destinos OTLP externos.

Segurança do Dashboard

ProtectionImplementation
AutenticaçãoSupabase Auth com sessões baseadas em cookies (httpOnly, secure, sameSite: lax)
Acesso à organizaçãoToda server action valida a associação do usuário via requireOrgAccess()
Operações administrativasAções destrutivas exigem requireOrgAdmin() (papel de owner ou admin)
Headers de segurançaX-Frame-Options: DENY, X-Content-Type-Options: nosniff, HSTS (2 anos), Permissions-Policy (câmera/microfone/geolocalização desabilitados)
Content Security PolicyRestringe origens de scripts, frame ancestors e alvos de conexão
Segurança de queriesTodas as queries do ClickHouse usam sintaxe parametrizada {name:Type} — sem interpolação de strings
Rate limiting120 requisições/minuto por usuário em todas as server actions
Limite de tamanho do bodyLimite de 2 MB nos payloads de server actions

Controle de Acesso Baseado em Papéis

O Floopy utiliza um modelo RBAC de três camadas para que o acesso concedido em um escopo mais amplo (um grupo de organizações) flua para todos os recursos dentro daquele escopo, enquanto associações mais específicas permanecem autoritativas no seu próprio nível.

Os três escopos

EscopoTabela no SupabaseO que controla
Grupoorganization_group_membersTodas as organizações que pertencem ao grupo (e, transitivamente, todos os projetos dentro dessas organizações).
Organizaçãoorganization_membersUma única organização e todos os projetos dentro dela.
Projetoproject_membersUm único projeto apenas.

Um usuário pode aparecer em qualquer combinação dessas tabelas. A função SQL has_org_access(auth.uid(), org_id) as avalia em conjunto e é o único predicado usado por todas as políticas de Row-Level Security no Supabase — não há lógica específica por tabela que possa divergir.

Herança de Acesso

has_org_access retorna true se qualquer uma das condições abaixo for verdadeira:

  1. O chamador é membro direto da organização alvo (organization_members).
  2. O chamador é membro do grupo da organização (organization_group_members juntado via organizations.organization_group_id).
  3. O chamador é membro de pelo menos um projeto dentro da organização alvo (project_members juntado via projects.organization_id).

Isso significa que um “dono de grupo” automaticamente tem acesso a toda organização e projeto sob o grupo, sem precisar de uma segunda linha de associação por recurso. Remover a associação no grupo remove o acesso a toda a subárvore em uma única operação.

Papéis dentro de um Escopo

Cada linha de associação carrega um campo role. Papéis são locais ao escopo — ser admin de um grupo não faz de você admin de um projeto específico dentro dele, a menos que você também tenha um papel no nível do projeto. Escopos definem alcance; papéis definem o que você pode fazer dentro daquele alcance.

PapelCapacidades típicas
ownerControle total, incluindo transferência de propriedade e exclusão do próprio escopo.
adminGerenciar membros, chaves e configurações neste escopo.
memberLer e usar recursos; não pode gerenciar membros ou configurações destrutivas.

O dashboard impõe papéis via requireOrgAdmin() (owner/admin) e requireOrgAccess() (qualquer membro). O gateway usa has_org_access indiretamente — chaves de API são escopadas a uma única organização, então acesso cruzado entre orgs nunca chega ao gateway.

Row-Level Security

Toda tabela que carrega tenant no Supabase (prompts, routing_rules, organization_api_keys, feedback, etc.) tem uma política RLS na forma:

USING (has_org_access(auth.uid(), organization_id))

Essa é a única verificação de acesso nessas tabelas. Acesso SQL direto através do cliente Supabase é tão seguro quanto acesso via server action pelo Zeus, porque ambos passam pela mesma política. Um token comprometido no lado do cliente ainda só pode ler linhas que o usuário subjacente já está autorizado a ler.

Rede e Transporte

ComponentTransport Security
Cliente → GatewayHTTPS (TLS 1.2+) via CDN/load balancer
Gateway → ProvedoresHTTPS para todos os provedores (OpenAI, Anthropic, etc.)
Gateway → Redisrediss:// (TLS) em produção
Gateway → ClickHouseHTTPS em produção
Dashboard → SupabaseHTTPS (gerenciado pelo Supabase)

Segurança do Fluxo de Requisição

Cada requisição passa por essas camadas em ordem. Cada camada pode rejeitar a requisição de forma independente:

  1. Verificação do tamanho do body — requisições acima de 10MB são rejeitadas imediatamente
  2. Rate limit por IP — requisições não autenticadas limitadas a 20 rpm por IP
  3. Validação da chave de API — chave extraída, hasheada, verificada contra cache/banco de dados
  4. Rate limit por organização — requisições autenticadas limitadas por organização
  5. Verificação de assinatura — planos expirados são rejeitados com 403 SUBSCRIPTION_EXPIRED
  6. Limites de uso — cotas mensais de requisições aplicadas, retorna 429 MONTHLY_LIMIT_EXCEEDED
  7. Resolução de prompt — se estiver usando prompts gerenciados, variáveis de template são substituídas
  8. Verificação de cache — se o cache estiver habilitado, verificado antes que qualquer operação sensível chegue ao provedor
  9. LLM Firewall — consulta ao cache de vereditos seguida de classificacao por LLM ajustado para seguranca
  10. Validação de SSRF — URL de saída verificada contra lista de permissões de provedores
  11. Sanitização de headers — headers perigosos removidos antes do encaminhamento
  12. Envio ao provedor — requisição encaminhada com headers limpos e autenticação do provedor injetada
  13. Logging assíncrono — resposta registrada com remoção de PII, sem nunca bloquear o caminho de resposta

Garantias de Segurança do Rust

O gateway é escrito em Rust, que oferece garantias em tempo de compilação contra:

  • Buffer overflows — arrays com verificação de limites, sem gerenciamento manual de memória
  • Desreferência de ponteiro nuloOption<T> imposto pelo sistema de tipos
  • Data races — o borrow checker impede acesso mutável concorrente
  • Use-after-free — o modelo de ownership elimina ponteiros pendentes
  • Vazamentos de memória — semântica de drop determinística (sem garbage collector)

Essas não são verificações em tempo de execução — são detectadas em tempo de compilação. Código que viola a segurança de memória simplesmente não compila.

Relato de Vulnerabilidades

Se você descobrir uma vulnerabilidade de segurança, por favor reporte de forma responsável:

  • Email: security@floopy.ai
  • SLA de resposta: Confirmação em até 48 horas, triagem em até 7 dias
  • Safe harbor: Pesquisadores agindo de boa-fé não sofrerão ações legais
  • security.txt: Disponível em https://api.floopy.ai/.well-known/security.txt

Conformidade

A arquitetura de segurança do Floopy é projetada com prontidão para conformidade em mente:

  • Residência de dados — logs armazenados na região de sua escolha
  • Retenção de dados — configurável por plano, aplicada via limpeza automatizada
  • Trilha de auditoria — todos os eventos de segurança registrados para investigação de incidentes
  • Criptografia em repouso — chaves de provedor (XChaCha20-Poly1305), dados de log (criptografia do ClickHouse)
  • Criptografia em trânsito — TLS em todas as conexões
  • Controle de acesso — RBAC de três camadas (grupo / organização / projeto) com permissões baseadas em papéis (owner, admin, member) e Row-Level Security em SQL via has_org_access