UDENTIVA Plataforma Inteligente de Gestão Odontológica
SEGURANÇA

Modelo de Segurança da API

A segurança não é uma camada adicionada depois, é o centro da arquitetura. O isolamento de dados, a separação de identidade e a gravação idempotente estão impressos na camada mais profunda do código — não é uma configuração que possa ser desligada, é a forma como o sistema funciona.

Isolamento em nível de linha Gravação idempotente Consulta parametrizada Isolamento por loopback
Isolamento de dados

Isolamento em nível de linha — fail-closed

Em cada tabela com escopo de inquilino, o Row-Level Security FORCE do PostgreSQL está ativo; a política vincula cada linha à condição "tenant_id = current_setting('app.current_tenant')".

Uma consulta que chega sem o context de tenant definido retorna zero linhas — nem sequer um erro, apenas silenciosamente vazia. Ver os dados de uma clínica com a sessão de outra é arquiteturalmente impossível.

O teste de isolamento entre tenants é obrigatoriamente verde na integração contínua (CI); se estiver vermelho, o código não é mesclado.

Gravação atômica

Identidade local à transação, operação atômica

A identidade do inquilino é definida NO INÍCIO da transaction em cada operação de escrita e é válida apenas durante essa transaction; não fica presa ao pool de conexões nem vaza para outras requisições.

As operações multientidade (fatura + item + pagamento + baixa de estoque) são atômicas dentro de uma única transação: ou tudo é gravado em conjunto, ou nada é. Não há registro pela metade ou inconsistente.

Permissão

Permissão baseada em função (RBAC) imposta no servidor

O controle de permissão é feito na camada da API; nunca se confia no cliente ou na interface. Ocultar um menu no navegador diz respeito apenas à aparência — a decisão real está no servidor.

As mutações do núcleo (Fase 1) são protegidas conforme as funções de admin, recepção e médico. Mesmo que uma função não autorizada chame o endpoint, a requisição é recusada.

Proteção contra repetição

Gravação idempotente — sem operação em duplicidade

Cada requisição de gravação carrega uma Idempotency-Key; o bloqueio no lado do servidor impede uma segunda operação que chegue com a mesma chave.

Mesmo quando a rede cai ou o cliente reenvia a mesma solicitação, não é criada uma segunda cobrança ou fatura. O resultado é sempre único e previsível.

Segurança de consulta

SQL injection impossível — consulta parametrizada

Todas as consultas ao banco de dados são instruções totalmente parametrizadas, geradas em tempo de compilação com o sqlc. Não há uma única linha na base de código que construa SQL concatenando strings manualmente com entrada do usuário.

Isso elimina estruturalmente a classe de ataques de SQL injection — não depende de "filtragem" ou "escape", mas da forma como a consulta é construída.

Superfície de rede

Isolamento por loopback — núcleo fechado ao exterior

A API central escuta apenas 127.0.0.1 (loopback). Qualquer tentativa de vincular a 0.0.0.0 ou a um IP público é rejeitada na inicialização; a central nunca fica exposta à internet, em hipótese alguma.

A única superfície pública é uma porta fina (BFF): não retém regras de negócio além de sessão, renderização e CSRF. O navegador nunca consegue ver nem endereçar diretamente a API central.

Identidade e sessão

Senha argon2id, chave de sessão opaca

As senhas são geradas com hash usando argon2id, um padrão do setor resistente à memória; hashes fracos ou em texto simples não são utilizados.

As chaves de sessão são valores opacos criptograficamente aleatórios de 32 bytes, armazenados no Redis e expirados por TTL. Ao navegador só se reflete um cookie HttpOnly + Secure + SameSite; a chave nunca é exposta ao JavaScript.

Auditoria

Log de auditoria imutável (append-only)

As operações importantes são gravadas no log de auditoria append-only dentro da MESMA transação que as dispara. Se a operação for revertida, o log de auditoria também não é gravado — os dois são inseparáveis.

A permissão de UPDATE/DELETE foi retirada da tabela de auditoria; os registros não podem ser editados nem excluídos posteriormente. O histórico permanece como está.

Privacidade

Mascaramento de dados sensíveis

TCKN, senha, chave de sessão e dados de saúde não entram nos logs de forma alguma. Esses campos são mascarados até mesmo nas saídas de depuração.

Quando necessário, os campos sensíveis são criptografados em nível de coluna. Os dados de saúde de natureza especial são protegidos por regras embutidas desde o início do projeto.

Integridade monetária

Segurança monetária — numeric, lançamento reverso

O dinheiro é mantido em todos os lugares como numeric(14,2); não se faz cálculo monetário com float. O arredondamento ocorre em um único ponto, no servidor — não há deslocamento de centavos nem diferença de arredondamento.

O cancelamento e o estorno são processados como um lançamento reverso, em vez de excluir o registro. O saldo de conta corrente não é escrito manualmente; é sempre derivado do total de faturas e pagamentos. O histórico não é corrompido.

Transferência

Segurança de transporte e navegador

Todo o tráfego é transportado por HTTPS/TLS e o HSTS está ativo; o navegador estabelece a conexão apenas de forma criptografada.

Uma política rígida de segurança de conteúdo (CSP) bloqueia scripts inline; X-Frame-Options DENY previne clickjacking e X-Content-Type-Options nosniff previne a confusão de tipos. Referrer-Policy e Permissions-Policy também são aplicadas.

Importante

Separação de tier de identidade + plano de administração separado

Usuário da clínica, portal do paciente e operador da plataforma são tiers de identidade SEPARADOS: cabeçalho separado, espaço de sessão separado. A chave de um tier não funciona em outro — os limites de autorização são estritamente separados.

Os endpoints de plataforma e administração (provisionamento de inquilino, faturamento, gestão de automação/plugins, geração de chaves de API) NÃO ESTÃO presentes na API pública.

Essas funções operam em um plano de controle separado, interno, com um padrão de identidade diferente (chave de administração dedicada); ele não é acessível nem detectável do exterior. Assim, a superfície de ataque é reduzida de forma significativa.

COMO FUNCIONA

Transação única, isolamento fail-closed

O fluxo conceitual abaixo mostra como cada gravação é bloqueada ao tenant e permanece idempotente. É apenas ilustrativo.

# 1) O contexto do inquilino é estabelecido NO INÍCIO da transaction (exclusivo apenas dessa tx)
BEGIN;
  SELECT set_config('app.current_tenant', :session_tenant_id, true);

  # 2) Bloqueio de Idempotency-Key — a mesma chave não gera uma segunda operação
  SELECT lock_idempotency(:idempotency_key);

  # 3) Escrita de múltiplas entidades — todas atômicas em uma única tx
  INSERT INTO invoices  ...;   # RLS: tenant_id coberto automaticamente
  INSERT INTO payments  ...;
  INSERT INTO audit_log ...;   # append-only, mesma tx
COMMIT;

# Se o context não for definido, a política RLS não retorna nenhuma linha:
SELECT * FROM patients;  --> 0 linhas (não é erro, silenciosamente vazio)
Verificável de forma independente

Parte da segurança de transporte pode ser observada externamente: você mesmo pode inspecionar o certificado HTTPS/TLS da sua conexão e cabeçalhos de segurança de resposta, como HSTS e a política de segurança de conteúdo, pelas ferramentas de desenvolvedor do seu navegador. Nossas afirmações baseiam-se em controles de arquitetura, não em frases de marketing.

Tem alguma dúvida sobre a arquitetura de segurança?
Nossa equipe terá prazer em conversar com você sobre os detalhes técnicos e seus requisitos de conformidade.
Entre em Contato