Nordlet

← Blogue

Building an Accounting API That Survives an Audit

A practical guide to the security and audit controls a financial API needs before Dutch businesses trust it with their books.

Nordlet Team · · 12 min de leitura

Uma API de contabilidade que devolve um 200 OK num registo de pagamento não nos diz praticamente nada. Não confirma que o razonete (ledger) registou o lançamento, que o agente tinha autorização para o efetuar, que o montante passou na validação ou que alguém com autoridade o aprovou. Para as empresas nos Países Baixos, onde a autoridade fiscal espera que os registos possam ser reconstruídos e guardados durante sete anos, essa lacuna entre "o pedido foi bem-sucedido" e "os livros estão corretos" é o ponto onde as auditorias falham.

Estar preparado para uma auditoria é um objetivo de conceção operacional, não um certificado. Significa que a API preserva uma cadeia completa: agente autenticado para ação autorizada, passando por alteração de estado validada, aprovação, resultado no razonete e evidência à prova de adulteração. Tudo o que se segue foca-se em construir essa cadeia deliberadamente, em vez de assumir que a autenticação e o TLS tratam do assunto.

O que torna uma API de contabilidade "preparada para auditoria"

Um auditor que esteja a reconstruir uma transação precisa de responder a uma sequência específica de perguntas. Quem a iniciou? Tinha permissão para o fazer? A alteração passou na validação contabilística? Quem a aprovou? O que é que o razonete registou? É possível alterar esse registo à posteriori sem deixar rasto?

Se a sua API não conseguir responder a todas estas seis questões a partir dos seus próprios registos e modelo de dados, não está preparada para auditoria, por muito limpo que o código pareça. A maioria das APIs lida bem com a primeira pergunta e mal com o resto.

Os controlos que fecham essa lacuna dividem-se em vários grupos: estado contabilístico explícito, autorização em camadas, autenticação com âmbito definido, operações idempotentes, validação no lado do servidor, segregação de funções e registo à prova de adulteração. Estes controlos reforçam-se mutuamente. Uma autorização fraca compromete um registo de auditoria forte, pois deixa de ser possível confiar que o agente registado tinha legitimidade para realizar a ação.

Modele os estados contabilísticos antes de modelar os endpoints

O erro de conceção mais comum é tratar cada registo financeiro como um objeto livremente editável com operações de criar, ler, atualizar e apagar (create, read, update, delete). A contabilidade não funciona assim e um auditor dará por isso imediatamente se um lançamento de diário afixado puder ser substituído silenciosamente.

Cada recurso com relevância financeira necessita de uma máquina de estados explícita. Um lançamento de diário ou pagamento passa tipicamente por:

draft → submitted → approved → posted → settled

As correções não retrocedem nesse caminho. Um lançamento afixado que esteja incorreto recebe uma reversão associada ou um ajuste compensatório. O original permanece intacto.

Um conjunto viável de regras:

  • Os rascunhos podem ser editados por utilizadores autorizados.
  • Os registos submetidos só podem ser editados por funções (roles) permitidas ou devolvidos ao estado de rascunho.
  • Os registos aprovados exigem uma alteração controlada e uma nova aprovação.
  • Os registos afixados não podem ser substituídos nem apagados, apenas revertidos ou ajustados.
  • As alterações a períodos fechados exigem autorização superior, um motivo justificado e um evento de auditoria.

Uma tentativa de transição ilegal, como por exemplo editar um registo afixado, deve devolver um erro estável e, ainda assim, escrever um registo de auditoria. A tentativa falhada também constitui evidência.

É aqui que um razonete de partidas dobradas imutável justifica a sua existência. O razonete do Nordlet foi concebido para que cada transação chegue como um lançamento equilibrado e permanente, com o equilíbrio a ser garantido por um gatilho (trigger) de base de dados no momento da consolidação, ocorrendo as correções através de reversões e não de reescritas. Essa restrição parece restritiva durante o desenvolvimento e transforma-se naquilo em que o seu contabilista confia durante uma auditoria.

Autorize todos os pedidos e não apenas a autenticação

A autenticação prova quem está a efetuar a chamada. Não diz absolutamente nada sobre se esse chamador pode aceder a uma determinada fatura, diário ou entidade legal. O OWASP API Security Project coloca a autorização deficiente ao nível do objeto no topo da sua lista de riscos, precisamente porque as APIs expõem identificadores de objetos que facilitam o acesso entre inquilinos (tenants) quando faltam verificações.

Cada pedido a uma API financeira deve ser autorizado com base numa combinação de fatores e não apenas num token:

  • agente autenticado
  • aplicação cliente ou conta de serviço
  • inquilino (tenant)
  • entidade legal
  • ID do recurso
  • operação solicitada
  • estado atual do recurso
  • montante ou limiar da transação

Duas regras práticas importam mais do que todas as outras. Primeiro, derive o contexto do inquilino e do utilizador a partir da identidade autenticada e rejeite qualquer afirmação (claim) de inquilino ou função fornecida pelo cliente que entre em conflito com a mesma. Um chamador nunca deve poder declarar em nome de que empresa está a agir. Segundo, utilize a recusa por omissão (deny-by-default). Se nenhuma política conceder explicitamente uma ação, esta falha.

Teste ambas as direções. O acesso horizontal, em que um inquilino acede aos dados de outro inquilino, e o acesso vertical, em que um utilizador comum acede a funções de aprovação, afixação ou exportação. Ambos são comuns e ambos são catastróficos em dados contabilísticos.

O modelo de funções do Nordlet, com papéis de proprietário, administrador, contabilista, gestor, programador e visualizador em várias empresas sob uma única conta, existe para tornar esta separação aplicável em vez de ser apenas uma aspiração. Uma função de programador que consiga criar rascunhos de faturas não deve poder libertar pagamentos.

Delimite os tokens a capacidades de negócio e não a verbos CRUD

Para o acesso delegado, utilize as orientações de segurança atuais do OAuth 2.0 em vez de palavras-passe reutilizáveis ou chaves de API estáticas e abrangentes. A RFC 9700 representa a Prática Atual de Excelência (Best Current Practice) e estabelece requisitos claros para clientes e servidores de autorização: URIs de redirecionamento validados, PKCE quando aplicável, verificações de emissor e audiência, tempos de vida curtos para os tokens de acesso e rotação de tokens de atualização com revogação.

A decisão sobre o âmbito (scope) é onde o pensamento específico da contabilidade se evidencia. Âmbitos genéricos como read e write são praticamente inúteis para a segregação de funções. Os âmbitos devem mapear-se para capacidades:

  • journal:create e journal:approve são âmbitos separados.
  • Criar uma instrução de pagamento não confere permissão para a libertar.
  • A permissão de exportação é distinta da permissão de leitura, uma vez que a exportação em massa é um canal de fuga de dados.

Seja preciso quanto ao posicionamento de um determinado produto nessa escala. As chaves de API do Nordlet transportam âmbitos por módulo, tais como sales:read e sales:write, verificados em cada ação, o que separa os módulos e a leitura da escrita, mas não a criação da aprovação; quando precisar dessa divisão mais fina atualmente, aplique-a no seu próprio serviço antes da chamada.

Para operações de elevado valor, vale a pena avaliar se se aplica o Perfil de Segurança FAPI 2.0. Foi concebido para APIs que protegem dados financeiros sensíveis e oferece garantias mais fortes do que o OAuth de base. A maioria das integrações de contabilidade para PME não precisará do perfil completo, mas os fluxos de libertação de pagamentos e de ligação bancária são os locais a considerar.

O início de sessão sem palavra-passe do Nordlet através de links de correio eletrónico de utilização única elimina o problema da palavra-passe reutilizável para utilizadores humanos, o que representa menos uma credencial para rodar, vazar ou sofrer de phishing.

Torne as operações de escrita financeira idempotentes

As redes falham a meio de um pedido. Um cliente envia uma instrução de pagamento, a ligação vai abaixo antes de a resposta chegar e o cliente tenta novamente. Sem proteção, passa a ter dois pagamentos.

As chaves de idempotência resolvem este problema. O cliente envia uma chave única com cada operação de escrita; o servidor regista a chave e o respetivo resultado. Uma nova tentativa com a mesma chave devolve o resultado original em vez de criar um segundo registo. O Nordlet aceita um cabeçalho Idempotency-Key em cada chamada de mutação, reproduzindo a resposta armazenada numa nova tentativa com a mesma carga útil (payload) e rejeitando a mesma chave se a carga útil tiver sido alterada. Qualquer API de contabilidade que ignore esta funcionalidade acabará por produzir lançamentos duplicados no razonete que alguém terá de deslindar manualmente.

Combine isto com a validação no lado do servidor. Nunca confie no cliente para verificar se os débitos são iguais aos créditos, se uma taxa de IVA é válida para o país e período, ou se uma conta existe. A validação é executada no servidor, antes da transição de estado, e uma escrita rejeitada produz um erro estável e um registo de auditoria.

Pistas de auditoria à prova de adulteração e retenção neerlandesa

O registo de auditoria é a camada de evidência e possui requisitos diferentes dos dados comerciais comuns. Deve registar a decisão de autorização, a versão da política, o agente, o objeto, a operação, o estado anterior e o novo estado, bem como o código de Justificação, sem nunca registar segredos ou credenciais de pagamento completas.

A propriedade crítica é a prova de adulteração. Se um administrador puder editar ou apagar discretamente os registos de auditoria, o registo não prova nada. O armazenamento exclusivo de anexação (append-only), o encadeamento criptográfico ou a retenção de escrita única (write-once) resolvem este problema. O ponto fundamental é que qualquer modificação deve ser detetável.

A retenção merece a sua própria política, separada da eliminação de registos comerciais. Nos Países Baixos, o período geral de retenção para registos administrativos é de sete anos e, para registos relativos a imóveis, estende-se até aos dez anos. Os seus fluxos comuns de eliminação de dados e de apagamento ao abrigo do RGPD não devem conseguir destruir registos ou evidências de auditoria que uma regra de retenção legal ainda cubra. Defina regras de retenção legal, arquivo e eliminação para evidências de auditoria de forma independente e mapeie-as para as jurisdições onde opera.

O fecho de período (period locking) apoia esta vertente ao nível contabilístico. Uma vez fechado um mês, os lançamentos nele contidos não podem ser alterados sem autorização superior e um motivo registado. O Nordlet aplica o fecho de período para que os meses fechados permaneçam fechados, rejeitando qualquer lançamento datado de um período fechado mesmo através da API, o que constitui uma das primeiras coisas que um auditor neerlandês verifica.

Proteja as extremidades: webhooks, exportações e integrações

A API principal é habitualmente a parte mais bem protegida do sistema. As extremidades apresentam fugas.

Os webhooks representam um risco de pedido falsificado. Um evento como sale_invoice.paid deve ser assinado para que o recetor possa verificar se provém de si, e os recetores devem tratar a entrega como "pelo menos uma vez" (at-least-once) e utilizar o ID do evento para desduplicação. O Nordlet assina cada entrega de webhook com uma assinatura HMAC sobre o corpo bruto e tenta novamente as entregas falhadas com intervalo exponencial (exponential backoff), pelo que o recetor tem de verificar a assinatura e desduplicar por ID de evento em vez de assumir uma entrega exatamente uma vez (exactly-once).

As exportações constituem um canal de fuga de dados em massa. As exportações de relatórios em XLSX, PDF ou JSON extraem grandes volumes de dados financeiros numa única operação, pelo que necessitam da sua própria permissão, limites de frequência (rate limits) e registo de auditoria. As integrações de terceiros que consome devem ser tratadas como dados não fidedignos, sendo validadas da mesma forma que valida os pedidos diretos dos clientes.

Lista de verificação de preparação para auditoria para uma API de contabilidade neerlandesa

Utilize esta lista antes de afirmar que uma integração está pronta para auditoria:

  • Máquina de estados explícita em cada recurso financeiro; os lançamentos afixados não podem ser substituídos
  • Autorização ao nível do objeto e da entidade legal em cada pedido, com recusa por omissão
  • Contexto de inquilino e função derivado do token e não de declarações do cliente
  • OAuth 2.0 em conformidade com a RFC 9700; âmbitos baseados em capacidades; separação entre criar e aprovar
  • Segregação de funções aplicada nos papéis e não apenas documentada
  • Chaves de idempotência em todas as operações de escrita financeira
  • Validação contabilística e de IVA no servidor antes das transições de estado
  • Registo de auditoria exclusivo de anexação e à prova de adulteração com códigos de motivo
  • Regras de retenção e retenção legal mapeadas para os períodos neerlandeses (sete anos, dez para propriedades)
  • Fecho de período nos meses fechados
  • Webhooks assinados com desduplicação; exportações com âmbito e limite de frequência definidos, e devidamente registadas

O que construiríamos primeiro

Se estivéssemos a integrar a contabilidade numa plataforma neerlandesa amanhã, começaríamos pelo modelo de estados e pela autorização ao nível do objeto, antes de escrever um único endpoint de negócio. Essas duas decisões condicionam tudo a jusante, e adaptá-las posteriormente a um sistema que tratava os lançamentos do razonete como linhas editáveis é genuinamente penoso. A idempotência e o registo de auditoria vêm a seguir, porque são baratos de adicionar numa fase inicial e dispendiosos quando adicionados depois de os dados estarem a fluir.

O resto — tokens com âmbito, webhooks assinados, fecho de período — surge com mais naturalidade assim que a base se sustenta. Tudo isto pode ser testado numa empresa em sandbox antes de tocar em quaisquer dados de produção.

FAQ

Uma API pronta para auditoria significa que a empresa está em conformidade?

Não, e convém ser preciso quanto a este ponto. A preparação para auditoria é uma propriedade de conceção do sistema: o razonete, os controlos e a cadeia de evidência são construídos para que uma auditoria possa ser bem-sucedida. A conformidade com um quadro fiscal, contabilístico ou de segurança específico é uma avaliação separada que mapeia esses controlos para uma norma nomeada. Uma API bem construída facilita o trabalho de conformidade; não o substitui.

Durante quanto tempo os registos contabilísticos precisam de ser guardados nos Países Baixos?

A obrigação geral é de sete anos para registos administrativos, estendendo-se até dez anos para registos associados a bens imóveis. Crie regras de retenção e de retenção legal que os seus fluxos comuns de eliminação não consigam sobrepor.

Uma chave de API estática é suficiente para uma integração financeira?

Para a automatização servidor-a-servidor com um âmbito restrito pode funcionar, mas as chaves estáticas reutilizáveis são difíceis de rodar e perigosas se forem divulgadas. Para o acesso delegado e qualquer fluxo centrado no ser humano, o OAuth 2.0 com tokens de curta duração e âmbito limitado por capacidades é a escolha mais sólida.

Porque é que a idempotência é tão importante especificamente para a contabilidade?

Porque uma escrita duplicada na maioria dos sistemas é um aborrecimento, enquanto uma escrita duplicada na contabilidade representa um número errado nos livros que alguém tem de localizar e reverter. As chaves de idempotência tornam as novas tentativas seguras em vez de arriscadas.

Leitura complementar